home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-07-19 | 4.7 MB | 104,452 lines | [TEXT/MPS ] |
Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
- æKY CopyrightNotice
- æC Copyright Apple Computer, Inc. 1985-1990, All rights reserved.
- 411 - Inside Macintosh Help - MPW 3.2 Beta Release.
- Wednesday, May 30, 1990 10:06:43 AM
-
- Information source: SpInsideMacintosh 1.0 HyperCard stack.
- Pegasus 1.2.5 Hypercard Stack IM Vol VI
- æKY Help
- InsideMacintoshHelp
- æC
- AboutInsideMacintoshHelp Preface UserInterfaceGuide
- IntroductiontoSystem7.0 RoadMap UserInterfaceGuideVI
- WorldwideSoftwareOverview
-
- AliasManager HelpManager ScriptManager
- AppleTalkManager ListManager SCSIManager
- ColorManager MemoryManager ShutdownManager
- ControlManager MenuManager SlotManager
- DatabaseAccessManager NotificationManager SoundManager
- DeferredTaskManager OSEventManager StartManager
- DeskManager PackageManager TimeManager
- DeviceManager PaletteManager ToolboxEventManager
- DialogManager PowerManager VerticalRetraceManager
- EditionManager PrintingManager WindowManager
- EventManager ProcessManagement
- FileManager QuickDraw
- FontManager ResourceManager
- GraphicsDevicesManager ScrapManager
-
-
- AppleDesktopBus FloatingPointPackage SoundDriver
- BinaryDecimalConversion GraphicsOverView StandardFile
- ColorPickerPackage InternationalUtilities SystemErrorHandler
- ColorQuickDraw MacintoshHardware SystemResourceFile
- CompatibilityGuidelines MemoryManagement TextEdit
- ControlPanels OSUtilities ToolboxUtilities
- DiskDriver PPCToolbox UsingAssemblyLanguage
- DiskInitialization SegmentLoader
- FinderInterface SerialDrivers
-
-
- A.ResultCodes C.SystemTraps SystemErrors
- B.MovesMemory D.GlobalVariables Glossary
-
-
-
-
- æKY AboutInsideMacintoshHelp
- æC
- ------------------------------------------------------------------------------
- Version 1.0 Beta:
-
- Volume VI chapters have been added to this version which contain information
- about System 7.0, new managers and changes to previous ones.
-
- New manager chapters are:
- AppleTalk Manager
- DatabaseAccess Manager
- Edition Manager
- Event Manager
- GraphicDevices Manager (Replaces the Graphic Devices chapter in Volume V)
- Help Manager
- Memory Management
- Power Manager
- PPC Toolbox
- Process Management
-
- Changed chapters are:
- Alias Manager
- Color Picker Package
- Color Quikdraw
- Control Panels
- File Manager
- FinderInterface
- Font Manager
- Notification Manager
- Palette Manager
- Resource Manager
- Slot Manager
- Sound Manager
- TextEdit
- Time Manager
-
- New/changed documentation chapters are:
- Compatibility Guidelines
- Graphics Overview
- Introduction to System 7.0
- Preface
- UserInterface Guidelines VI
- Worldwide Software Overview
-
- ------------------------------------------------------------------------------
- Version 1.0 Alpha:
-
- InsideMacintoshHelp file provides on-line documentation for the 411 project.
- This version contains all the chapters of InsideMacintosh Volumes I - V.
- æKY AliasManager
- æC
- _______________________________________________________________________________
-
- ALIAS MANAGER
- _______________________________________________________________________________
-
- About…the…Alias…Chapter
- About…the…Alias…Manager
- About…Alias…Records
- Strategies…for…Resolving…Alias…Records
- Fast…Search
- Slow…Search
- Using…the…Alias…Manager
- Creating…Alias…Records
- Resolving…Alias…Records
- ResolveAlias
- SelectAlias
- MatchAlias
- Reading…Alias…Records
- Maintaining…Alias…Records
- Storing…and…Retrieving…Alias…Records
- Alias…Manager…Routines
- Creating…and…Updating…Alias…Records
- Resolving…and…Reading…Records
- Summary…of…the…Alias…Manager
- Alias…Constants
- Alias…Data…Types
- Alias…Routines
- Alias…Result…Codes
- Assembly-Language…Information…for…Alias
- _______________________________________________________________________________
-
-
-
- æKY About…the…Alias…Chapter
- æC »ABOUT THIS CHAPTER Alias Manager
- _______________________________________________________________________________
-
- This chapter describes how your application can use the Alias Manager to
- establish and resolve alias records, which are data structures that describe a
- file, folder, or volume.
-
- You create an alias record to take a fingerprint of an object, usually a file,
- that you might need to locate again later. If you store the alias record,
- instead of a conventional file specification such as name and parent directory
- ID, you can later use the Alias Manager’s algorithms for finding files that have
- been moved, renamed, copied, or restored from backup.
-
- Note: The Alias Manager is a utility for exploiting alias records. It does not
-
- directly manipulate desktop aliases, which are created and managed by the
-
- Finder. (The Finder Interface chapter describes desktop aliases.)
-
- The Alias Manager is available only in system software version 7.0. Call the
- Gestalt function, described in the Compatibility Guidelines chapter of this
- volume, to determine whether the Alias Manager is present.
-
- Read this chapter if you want your application to create and resolve alias
- records. You might use an alias record, for example, to identify a customized
- dictionary from within a text document. When the user runs a spelling checker on
- the document, your application can ask the Alias Manager to resolve the record
- to find the correct dictionary.
-
- To use this chapter, you should be familiar with the File Manager’s conventions
- for identifying files, folders, and volumes, as described in the File Manager
- chapters in volume IV and this volume.
-
- _______________________________________________________________________________
-
- æKY About…the…Alias…Manager
- æC »ABOUT THE ALIAS MANAGER Alias Manager
- _______________________________________________________________________________
-
- The Alias Manager creates and resolves alias records. The next section, “About
- Alias Records,” describes how you can use alias records.
-
- In general, you should use the Alias Manager whenever you find yourself storing
- specific file or directory information such as full pathname or filename and
- parent directory ID. The Alias Manager stores this information and more in the
- alias record, and it also provides a set of search strategies for resolving the
- record later. The search strategies are described in “Resolving Alias Records,”
- later in this chapter.
-
- You can use the Alias Manager to
- • create and resolve alias records
- • get information from and update alias records
-
- The Alias Manager can track files and folders across volumes. If the target of
- an alias record is on an unmounted AppleShare® volume, the Alias Manager can
- automatically initiate the mounting when it resolves the alias. If the target
- object is on an unmounted ejectable disk, the Alias Manager can prompt the user
- to insert the disk.
-
- When the Alias Manager creates an alias record, it fills in the record and
- returns a handle to it. Your application must store and retrieve the records on
- disk if necessary. Your application must also supply strategies for handling
- various alias-resolution problems, described in “Resolving Alias Records.”
-
- To help you understand and use the Alias Manager, this chapter provides
- • an overview of alias records
- • a description of how the Alias Manager resolves alias records
- • specific techniques for using the Alias Manager in your application
- _______________________________________________________________________________
-
- æKY About…Alias…Records
- æC »ABOUT ALIAS RECORDS Alias Manager
- _______________________________________________________________________________
-
- An alias record is a data structure that describes a file, folder, or volume.
- The record contains a collection of information about its target, including its
- name and file ID, creation date, parent directory name and ID, and volume name
- and creation date.
-
- By storing alias records, you can allow your users to create robust connections
- between files—--that is, connections that can survive the moving or renaming of
- one or both files. The Finder™ in system software version 7.0 stores an alias
- record when the user creates a desktop alias object. The Edition Manager uses
- alias records to implement data-sharing among separate documents. (The Finder
- Interface and Edition Manager chapters in this volume describe those features in
- detail. The section “Using the Alias Manager,” later in this chapter, describes
- how the Finder and the Edition Manager call the Alias Manager.)
-
- The alias record itself contains two kinds of information: public information
- available to your application and private information used by the Alias Manager.
-
- TYPE
- AliasHandle = ^AliasPtr;
- AliasPtr = ^AliasRecord;
- AliasRecord =
- RECORD
- userType: OSType; /* application’s signature */
- aliasSize: Integer /* record size when created */
- {variable-length private data}
- END;
-
- Your application can use the userType field to store its own signature or any
- other data that fits in four bytes. When the Alias Manager fills in an alias
- record, it stores four spaces (0x20202020) in that field.
-
- The Alias Manager stores the size of the record when it was created in the
- aliasSize field. Knowing the starting size allows your application to store and
- retrieve data of its own at the end of the record. First, expand the size of the
- record with the Memory Manager, described in Volume II. You can then find the
- starting address of your own data in the record by adding the record’s starting
- address to its original length, as reported in the aliasSize field.
-
- The private Alias Manager data includes a collection of file, directory, and
- volume names and their creation dates; file and directory IDs; a full pathname,
- including the volume name; and, if applicable, AppleShare information for use in
- resolving the alias record.
-
- When you create an alias record, you have the option of recording a relative
- path, that is, the path to the target object from another file or folder on the
- same disk. The beginning point of a relative path is called the fromFile. To
- record relative path, the Alias Manager saves the distances from the target and
- the fromFile to the common parent, that is, the lowest-level directory that
- appears in the pathnames of both. The Alias Manager can later use those
- distances in conjunction with the absolute pathname to conduct a relative
- search.
-
- Suppose, for example, that you are writing a word-processing application that
- allows the user to build a customized, supplemental dictionary for each
- document. You create the dictionary as a separate document in the same folder as
- the document it serves, as Figure 24-1 shows.
-
- ø 24.1 Recording of Relative Path
-
- When resolving the alias record using relative path, the Alias Manager starts at
- the directory the specified distance above the fromFile, the directory named
- Sample in the example above. The Alias Manager then constructs a pathname by
- using one field of the absolute pathname for each step from the target to the
- common parent. In this example, the distance is one, so the pathname contains
- only the name of the target document, Dictionary.
-
- In some circumstances, a relative search identifies the correct target when an
- absolute search could not. For example, suppose the user of your word-processing
- application creates a working copy of a document and dictionary by copying the
- entire folder Sample to another disk. The user later updates the original
- document and dictionary by copying the folder from the working disk. All of the
- underlying file and folder identifications change, but the filenames and
- relative path remain the same. When the user later runs the spelling checker on
- the document, a relative-path search finds the target dictionary.
-
- The Alias Manager accepts and returns file specifications only in the form of
- file system specification records (FSSpec records), described in the File
- Manager chapter of this volume. The FSSpec record represents the simlest
- complete description of a file system object. It contains a volume reference
- number, a parent directory ID, and a name.
-
- _______________________________________________________________________________
-
- æKY Strategies…for…Resolving…Alias…Records
- æC »STRATEGIES FOR RESOLVING ALIAS RECORDS Alias Manager
- _______________________________________________________________________________
-
- The Alias Manager provides three alias-resolution functions:
-
- • The high-level function ResolveAlias performs a fast search for a single
- target. If the target resides on an unmounted volume, ResolveAlias
- attempts to mount the volume automatically. If it finds no match for the
- alias record, ResolveAlias simply returns an error code.
-
- • The high-level function SelectAlias can identify more than one possible
- target. If it identifies either no targets or more than one possible
- target, it displays a dialog box, through which the user can direct the
- search. SelectAlias starts with a fast search and can perform a slow
- search at the user’s request. (Fast and slow searches are described
- below.) If the target resides on an unmounted volume, SelectAlias
- attempts to mount the volume automatically.
-
- • The low-level function MatchAlias accepts a set of input rules to control
- the search. MatchAlias can perform either a fast or a slow search. It can
- identify and return multiple possible targets. Your program must process
- the results.
-
- The following sections describe the fast- and slow-search algorithms the Alias
- Manager uses to resolve alias records. For information on using the functions,
- see “Using the Alias Manager” and “Alias Manager Routines” later in this
- chapter.
-
- _______________________________________________________________________________
-
- æKY Fast…Search
- æC »Fast Search Alias Manager
- _______________________________________________________________________________
-
- The fast-search algorithm is designed to find the most likely match for an alias
- record first. This strategy meets the needs of the ResolveAlias function, which
- exits as soon as it finds one match. The fast-search algorithm can, however,
- identify more than one possible target for presentation to the user through the
- SelectAlias function.
-
- The first step in the search is to identify the volume on which the target
- resides, using the volume’s name, creation date (which acts almost as a unique
- identifier for a volume), and volume type (for example, a hard disk, a 3.5-inch
- disk, or an AppleShare volume).
-
- The Alias Manager first looks for a volume by both name and creation date. The
- search succeeds if the volume is mounted and if its name and creation date have
- not changed since the record was created. If the target is on an unmounted
- AppleShare volume, the Alias Manager attempts to mount the volume. If the target
- is on an unmounted ejectable disk, the Alias Manager presents the switch-disk
- dialog box, illustrated in Figure 24-2.
-
- ø 24.2 Switch-Disk Dialog Box
-
- If the target volume is not found by name and creation date, the Alias Manager
- attempts to match by creation date only. This step locates volumes that have
- been renamed. Finally, the Alias Manager attempts to match by volume name only.
-
- If none of these strategies results in a volume match, the Alias Manager returns
- nvsErr.
-
- Once the target volume is identified, fast search looks for the actual target,
- first by file ID (if the target is a file) or directory ID (if the target is a
- volume or directory). (File IDs are described in the File Manager chapter of
- this volume.) Even if a file has been renamed or moved on a volume, the File
- Manager can find it quickly through its file ID.
-
- If the search by file ID or directory ID fails, fast search looks for the target
- by name in the original parent directory. This search locates the target if its
- file or directory ID has changed but it still exists by the same name in the
- parent directory (for example, if the target was restored from backup). Fast
- search compares file numbers on files found by name in the correct parent
- directory. If the file numbers do not match, the file is treated as a possible
- match, that is, it is put on the list of candidates and the search continues. If
- the target is not found by name in the parent directory, fast search looks for a
- file by file number in the parent directory.
-
- If the search by file ID or directory ID fails, and if fast search cannot find
- the original parent directory, it searches for the target by full pathname. This
- search finds the target if it resides in the same location on the disk but the
- directory ID of its parent directory has changed (for example, if the entire
- parent directory was backed up and restored).
-
- If the full pathname fails, fast search attempts to find the file by tracing
- partial pathnames up through all parent folders, using parent directory IDs
- instead of folder names. For example, consider this full pathname:
-
- MyDisk:MyReports:January:Sales Report
-
- If the search by full pathname fails, fast search first looks for the partial
- pathname Sales Report in the directory MyDisk:MyReports:January. If that search
- fails, it looks for January:Sales Report in the directory MyDisk:MyReports, and
- so on.
-
- If the search by absolute pathname fails, and if your application requests a
- relative search, fast search performs a relative search. (For a description of
- relative path, see “About Alias Records” earlier in this chapter.) The search
- succeeds if the relative path is the same as when the record was created and if
- the names of the objects have not changed.
-
- _______________________________________________________________________________
-
- æKY Slow…Search
- æC »Slow Search Alias Manager
- _______________________________________________________________________________
-
- The slow-search algorithm uses the same strategy as fast search for identifying
- the volume.
-
- Once the volume is identified, slow search calls the File Manager function
- PBCatSearch, searching for objects with a matching creation date, creator, and
- type. (See the File Manager chapter for a description of PBCatSearch.) It
- searches the entire volume.
-
- PBCatSearch is available only on Hierarchical File System (HFS) volumes, not on
- Macintosh File System (MFS) volumes. (See the File Manager chapter of this
- volume for a description of the two file systems.) PBCatSearch is also available
- only on systems running version 7.0 and later. When searching an MFS volume or a
- volume on a file server running older system software, slow search performs a
- recursive search of the entire volume, searching for objects with matching
- creation date, type, creator, or file number.
-
- _______________________________________________________________________________
-
- æKY Using…the…Alias…Manager
- æC »USING THE ALIAS MANAGER Alias Manager
- _______________________________________________________________________________
-
- You use the Alias Manager primarily to create and resolve alias records. You can
- also use it to look at and update alias records.
-
- The Alias Manager creates an alias record in memory and provides you with a
- handle to the record. Your application can store the records on disk as
- resources of type 'alis' (see “Creating and Updating Alias Records”). When you
- no longer need the record in memory, call the DisposHandle procedure, described
- in the Memory Manager chapter of Volume II, to free the memory occupied by the
- record.
-
- All Alias Manager routines accept and return file specifications only in the
- form of FSSpec records, which contain a volume reference number, a parent
- directory ID, and a target name. Use the File Manager function MakeFSSpec to
- convert other forms of file identification, such as pathname, into a canonical
- file specification (see the File Manager chapter in this volume for a
- description of file identification conventions).
-
- For more detailed descriptions of the functions described in this section, see
- “Alias Manager Routines” later in this chapter.
-
- _______________________________________________________________________________
-
- æKY Creating…Alias…Records
- æC »Creating Alias Records Alias Manager
- _______________________________________________________________________________
-
- You create a new alias record by calling the NewAlias function. NewAlias fills
- in the record and provides a handle to it. NewAlias always records a collection
- of information about the target, including the full pathname. You can request
- that it store relative path information as well by supplying a starting point
- for a relative search.
-
- Call NewAlias when you want to store a file description for later use. For
- example, suppose you were writing a word-processing application that allows the
- user to customize a dictionary for use with a single text file. Your application
- stores the custom data in a separate file in the same folder as the document. As
- soon as you create the dictionary file, you call NewAlias to create an alias
- record for that file, including path information relative to the user’s text
- document:
-
- MyErr := NewAlias(textFilePtr, targetPtr, myAliasHdl);
-
- The parameter textFilePtr is a pointer to a FSSpec record that identifies the
- starting point for the relative search, in this case the user’s text file. If
- you do not want relative path information recorded, pass a value of NIL in the
- first parameter.
-
- The parameter targetPtr is a pointer to a FSSpec record that identifies the
- target file, in this example the dictionary file.
-
- The parameter myAliasHdl a variable in which the Alias Manager returns a handle
- to the target description.
-
- _______________________________________________________________________________
-
- æKY Resolving…Alias…Records
- æC »Resolving Alias Records Alias Manager
- _______________________________________________________________________________
-
- The Alias Manager provides three alias-resolution functions:
-
- • ResolveAlias, which simply searches for one target and exits if it fails
-
- • SelectAlias, which searches for all plausible targets and displays a
- dialog box to the user if it finds either more than one target or no
- targets
-
- • MatchAlias, which returns one or more targets
-
- ResolveAlias and SelectAlias are both high-level functions, which call the
- low-level function MatchAlias. The sections below describe the three functions
- in detail. The section “Strategies for Resolving Alias Records,” earlier in this
- chapter, describes the underlying search strategies used by the alias-resolution
- functions.
-
- In general, when you want to identify only the single most likely target of an
- alias record, you call ResolveAlias. When you want the user to guide the
- resolution of any ambiguous records, you call SelectAlias. When you want your
- program to control the search or branch depending on the outcome, you call
- MatchAlias.
-
- For example, the Finder stores a single alias record for each alias object that
- appears on the desktop. When the user opens an alias from the Finder, the Finder
- identifies the real object to be opened by resolving the alias record before it
- starts up the appropriate application. The Finder calls the ResolveAlias
- function, which either finds the target or exits.
-
- The Edition Manager follows a more complicated strategy, designed to shield the
- user from dialog boxes until they are necessary. Applications can use the
- Edition Manager to allow users to incorporate information from one document into
- another. When the user inserts shared data into a document, the Edition Manager
- stores an alias record that points to the edition, that is, the file that
- contains the shared data. Figure 24-3 illustrates how an alias record in a user
- document points to an edition.
-
- ø 24.3 How the Edition Manager Uses an Alias Record
-
- When the user opens a document that includes one or more sections of shared
- data, the Edition Manager first checks to see if any of the shared data is out
- of date. It then makes a quick attempt to resolve the alias records for all
- sections that need to be updated. It calls MatchAlias for each record,
- requesting a fast search with automatic mounting suppressed and a maximum of two
- matches. If MatchAlias finds only one match for a record, the Edition Manager
- accepts that candidate as the correct target. If MatchAlias finds no matches or
- two matches, the Edition Manager simply tags that record as unresolved. When the
- user tries to display or print a portion of the document that contains an
- unresolved record, the Edition Manager calls SelectAlias, which either finder
- the target or prompts the user to direct the search for the correct target. This
- strategy provides automatic resolution of unambiguous alias records, allows the
- user to resolve ambiguities, and delays alias-resolution dialogs until they are
- really necessary.
-
- _______________________________________________________________________________
-
- æKY ResolveAlias
- æC »ResolveAlias Alias Manager
- _______________________________________________________________________________
-
- In the simplest case, you can call the ResolveAlias function to resolve an alias
- record. ResolveAlias performs a fast search (described in “Strategies for
- Resolving Alias Records”) and exits after it identifies one target.
-
- ResolveAlias compares some key information about the identified target with the
- information stored in the alias record. If any of the information is different,
- ResolveAlias automatically updates the record.
-
- In the dictionary example, illustrated in Figure 24-1, above, the application
- calls ResolveAlias when the user runs the spelling-checker on an application
- with a customized dictionary.
-
- MyErr := ResolveAlias(textFilePtr, myAliasHdl, targetPtr, updateFlag);
-
- The parameter textFilePtr is a pointer to a FSSpec record that identifies the
- starting point for the relative search, in this case the user’s text file. If
- you do not want relative path information used in the search, pass a value of
- NIL in the first parameter.
-
- The parameter myAliasHdl points to the alias record to be resolved. In this
- example, the alias record describes the dictionary file.
-
- The parameter targetPtr is a is a pointer to the FSSpec record where the Alias
- Manager will place the results of its search. After ResolveAlias completes, the
- record pointed to by targetPtr contains the specification for the dictionary
- file.
-
- The ResolveAlias function uses the updateFlag parameter to report whether or not
- it updated the alias record. After ResolveAlias completes, updateFlag is TRUE if
- the record was updated and FALSE if it was not.
-
- _______________________________________________________________________________
-
- æKY SelectAlias
- æC »SelectAlias Alias Manager
- _______________________________________________________________________________
-
- If you want to let the user handle any ambiguities in the resolution, you can
- call the SelectAlias function to resolve an alias.
-
- The SelectAlias function always performs a fast search first. If the search
- identifies only one target, it behaves exactly like ResolveAlias. If the search
- identifies no targets or more than one possible target, the Alias Manager
- presents a dialog box like the one in Figure 24-4.
-
- ø 24.4 SelectAlias dialog box
-
- In this example, the user moved the original target file, Sales Report, to a
- different folder. Later, the user copied the file back into its original parent
- folder and renamed the original file, now in a different folder, Old Sales
- Report. The Sales Report file now appears in the correct parent directory with
- the correct name but a different file ID. The file Old Sales Report appears in a
- different parent directory with a different name but with the original file ID.
- The fast-search algorithm identifies both files as possible targets.
-
- The first field in the dialog box informs the user of the ambiguity. The message
- is fixed except for the name of the target and the type description, which is
- the word immediately before the target name (Edition in this example). You can
- control the type description through the fileTypeName parameter in the
- SelectAlias function. If you pass an empty string in this parameter, the Alias
- Manager substitutes the word document or folder, depending on what kind of
- object the alias describes. The name of the target is the original filename
- stored in the alias record.
-
- The left scroll list, labeled “Name:”, shows the names of all possible alias
- matches. The first entry is highlighted when the dialog box first appears.
-
- The right scroll list, labeled “Location:”, displays the full path of whatever
- entry is highlighted in the Name column. Entries in this list are not
- selectable.
-
- The Select button accepts the highlighted entry as the target of the alias
- record. When the user clicks Select, SelectAlias removes the dialog box and
- places the highlighted entry in the target parameter. Pressing the Enter or
- Return key or double-clicking an entry in the name list has the same effect as
- clicking Select.
-
- The Cancel button cancels the entire selection process. When the user clicks
- Cancel, SelectAlias removes the dialog box and returns userCanceledErr. Pressing
- the Esc (Escape) key or Command-period has the same effect as clicking Cancel.
-
- The Try Harder button triggers an asynchronous slow search of all mounted
- volumes, beginning, if possible, with the volume on which the target resided
- when the alias record was last updated. If the slow search identifies additional
- possible matches, the Alias Manager adds them to the name list. If the slow
- search takes more than three seconds in real time, the Alias Manager presents a
- dialog box that allows the user to cancel the search in progress. Once the Alias
- Manager has completed the slow search, it dims the Try Harder button.
-
- The Another One button lets the user override the entire selection process. The
- Alias Manager presents a dialog box much like the Standard File Package dialog
- box, which allows the user to select any file or folder on the system. Clicking
- OK accepts the highlighted object as the target of the search. While this dialog
- box is on the screen, clicking Cancel returns the user to the SelectAlias dialog
- box.
-
- In the dictionary example described above, the application could call
- SelectAlias instead of ResolveAlias so that the user can help locate the correct
- dictionary if a fast search fails to find it.
-
- MyErr := SelectAlias(textFilePtr, typeStr, NIL, myAliasHdl, targetPtr,
- updateFlag, NIL, NIL);
-
- The parameter textFilePtr is a pointer to a FSSpec record that identifies the
- starting point for the relative search, in this case the user’s text file. If
- you do not want relative path information used in the search, pass a value of
- NIL in the first parameter.
-
- The parameter typeStr points to a string containing the word Dictionary. When
- SelectAlias displays its dialog box, it uses this string to remind the user that
- the target is a dictionary file.
-
- The first NIL parameter tells SelectAlias that the application is not supplying
- a filter function to process the results of the search.
-
- The parameter myAliasHdl points to the alias record to be resolved. In this
- example, the alias record describes the dictionary file.
-
- The parameter targetPtr is a is a pointer to the FSSpec record where the Alias
- Manager will place the results of its search. After SelectAlias completes, the
- record pointed to by targetPtr contains the specification for the dictionary
- file.
-
- The SelectAlias function uses the updateFlag parameter to report whether or not
- it updated the alias record. After SelectAlias completes, updateFlag is TRUE if
- the record was updated and FALSE if it was not.
-
- The second NIL parameter controls the filtering of events by the ModalDialog
- procedure while the SelectAlias dialog box is on the screen. A value of NIL
- means that your application does no special filtering. (SelectAlias calls
- ModalDialog when it displays the SelectAlias dialog box. For a description of
- the ModalDialog procedure, see the Dialog Manager chapter of Volume I.) Because
- this example does not provide a custom filter function, it does not need to pass
- any data of its own, and it sets the final parameter to NIL.
-
- _______________________________________________________________________________
-
- æKY MatchAlias
- æC »MatchAlias Alias Manager
- _______________________________________________________________________________
-
- The MatchAlias function is a low-level routine that gives your program control
- over the searching algorithm.
-
- You can control the search by setting flags in the rulesMask parameter. The
- flags let you specify whether to attempt an automatic mounting of unmounted
- volumes; whether to search on more than one volume; and whether to perform a
- fast search, a slow search, or both. (For details about the rulesMask parameter,
- see “Alias Manager Routines” later in this chapter.) You can also specify a
- maximum number of candidates to be identified.
-
- MatchAlias returns all candidates that it identifies in an array of FSSpec
- records.
-
- You can use MatchAlias to perform a preliminary search for a target, branching
- to different routines depending on the outcome. The Edition Manager calls
- MatchAlias, as described in the introduction to this section, “Resolving Alias
- Records.”
- _______________________________________________________________________________
-
- æKY Reading…Alias…Records
- æC »Reading Alias Records Alias Manager
- _______________________________________________________________________________
-
- To retrieve information from an alias record without actually resolving the
- record, call the GetAliasInfo function. You can use GetAliasInfo to retrieve the
- name of the target, the names of its parent directories, the name of its volume,
- or, in the case of an AppleShare volume, the zone or server name.
-
- _______________________________________________________________________________
-
- æKY Maintaining…Alias…Records
- æC »Maintaining Alias Records Alias Manager
- _______________________________________________________________________________
-
- To update an alias record, call the UpdateAlias function. You can use
- UpdateAlias any time you know that the target of an alias record has been
- renamed or otherwise changed.
-
- You are most likely to call UpdateAlias after a call to the MatchAlias function.
- If MatchAlias identifies a single target, it sets a flag telling you whether or
- not the key information about the target file matches the information in the
- alias record. It is the responsibility of your application to update the record.
-
- The ResolveAlias and SelectAlias functions automatically update an alias record
- when the key information about the target they return does not match the record.
-
- _______________________________________________________________________________
-
- æKY Storing…and…Retrieving…Alias…Records
- æC »Storing and Retrieving Alias Records Alias Manager
- _______________________________________________________________________________
-
- Alias records are stored as resources of type 'alis'.
-
- CONST rAliasType = 'alis'
-
- To store and retrieve alias records, use the standard Resource Manager functions
- described in the Resource Manager chapter of Volume I.
-
- _______________________________________________________________________________
-
- æKY Alias…Manager…Routines
- æC »ALIAS MANAGER ROUTINES Alias Manager
- _______________________________________________________________________________
-
- This section describes the routines you use to create, update, read, and resolve
- alias records.
-
- All Alias Manager routines use file system specification records (FSSpec
- records) to identify files, folders, and volumes. To create a FSSpec record,
- call the function MakeFSSpec, described in the File Manager chapter of this
- volume.
-
- The Alias Manager routines can return the result codes listed in this section or
- any other applicable file system or memory management result codes. The file
- system result codes are listed in the File Manager chapter of Volume IV, and the
- memory management result codes are listed in the Memory Manager chapter of this
- volume.
-
- _______________________________________________________________________________
-
- æKY Creating…and…Updating…Alias…Records
- æC »Creating and Updating Alias Records Alias Manager
- _______________________________________________________________________________
-
- You use the NewAlias function to create an alias record.
-
- FUNCTION NewAlias (fromFile,target: FSSpecPtr; VAR alias: AliasHandle) : OSErr;
-
- NewAlias creates an alias record that describes the object specified in the
- target parameter. It fills in the record and puts a record handle in the alias
- parameter.
-
- The fromFile parameter represents the starting point for a relative search. This
- parameter can be either NIL or a pointer to a valid FSSpec record. If fromFile
- is NIL, the alias record does not include relative path information. Specify a
- value for fromFile only if you want NewAlias to record relative path
- information.
-
- The target parameter points to a FSSpec record for the file, folder, or volume
- to be described by the alias record.
-
- The alias parameter is the handle for the newly created alias record. If the
- function fails to create an alias record, it sets alias to NIL.
-
- Result codes
- paramErr -50 The target parameter is NIL
-
-
- You use the UpdateAlias function to update an alias record.
-
- FUNCTION UpdateAlias (fromFile,target: FSSpecPtr; alias: AliasHandle; VAR
- wasChanged: Boolean) : OSErr;
-
- UpdateAlias updates the alias record pointed to by the alias parameter so that
- it describes the file, folder, or volume specified by the target parameter.
- UpdateAlias rebuilds the entire alias record.
-
- The fromFile parameter represents the starting point for a relative search. This
- parameter can be either NIL or a pointer to a valid FSSpec record. If fromFile
- is NIL, the updated alias record does not include relative path information.
- Specify a value for fromFile only if you want UpdateAlias to record relative
- path information.
-
- The target parameter is the target of the alias record. This parameter must
- point to a valid canonical file specification record.
-
- The alias parameter points to the alias record to be updated.
-
- If the newly constructed alias record is exactly the same as the old one,
- UpdateAlias sets the wasChanged parameter to FALSE. Otherwise, it sets it to
- TRUE. Check this parameter to determine whether you need to save an updated
- record.
-
- Result codes
- paramErr -50 target, alias, or both are NIL, or the handle is corrupt
- _______________________________________________________________________________
-
- æKY Resolving…and…Reading…Records
- æC »Resolving and Reading Records Alias Manager
- _______________________________________________________________________________
-
- You use the ResolveAlias function to resolve an alias.
-
- FUNCTION ResolveAlias (fromFile: FSSpecPtr; alias: AliasHandle; VAR target:
- FSSpec; VAR wasChanged: Boolean) : OSErr;
-
- If the resolution is successful, ResolveAlias returns the FSSpec record for the
- target filename through the target parameter, updates the alias record if
- necessary, and reports whether or not the record was updated through the
- wasChanged parameter. If the target object is on an unmounted AppleShare volume,
- ResolveAlias automatically mounts the volume. If the target is on an unmounted,
- ejectable volume, ResolveAlias displays a switch-disk dialog box. ResolveAlias
- exits after it finds one acceptable target.
-
- The fromFile parameter represents the starting point for a relative search. This
- parameter can be either NIL or a valid FSSpec record. If fromFile is NIL,
- ResolveAlias does not perform a relative sesarch.
-
- The alias parameter points to the alias record to be resolved and, if necessary,
- updated.
-
- The Target parameter receives the FSSpec record of the target filename.
-
- If it updates the alias record, ResolveAlias sets the wasChanged parameter to
- TRUE. Otherwise, it sets it to FALSE. If the function returns an error code, it
- sets wasChanged to FALSE.
-
- Result codes
- nsvErr -35 The volume is not mounted
- fnfErr -43 No target was found
- paramErr -50 The alias parameter is NIL, or the handle is corrupt
-
-
- If you want the user to direct the search when an alias record cannot be
- resolved unambiguously, call the SelectAlias function.
-
- FUNCTION SelectAlias (fromFile: FSSpecPtr; fileTypeName: Str31; aliasFilter:
- ProcPtr; alias: AliasHandle; VAR target: FSSpec; VAR
- wasChanged: Boolean; filterProc: ProcPtr; callbackPtr:
- Ptr) : OSErr;
-
- If SelectAlias finds a single match for the record pointed to by the alias
- parameter, it behaves the same way as ResolveAlias. If SelectAlias finds no
- matches or more than one match for the record, the Alias Manager presents a
- modal dialog box that allows the user to direct the search and select the
- target. (See “User-Directed Search” for a description of the dialog box.)
-
- The fromFile parameter represents the starting point for a relative search. This
- parameter can be either NIL or a valid FSSpec. If fromFile is NIL, SelectAlias
- does not perform a relative search.
-
- The fileTypeName string is a descriptive name for the file type of the target
- object, intended to help the user select the correct target. It appears as part
- of the title of the dialog box.
-
- The aliasFilter parameter points to an optional filter function supplied by your
- application. The Alias Manager executes this function for each possible match
- that SelectAlias finds or after three seconds have elapsed without a match.
- Your filter function returns a Boolean value that determines whether the
- possible match is to be discarded (TRUE) or displayed (FALSE). It can also
- terminate the search. The function has three parameters.
-
- FUNCTION MySelectAliasFilter (paramBlock: CInfoPBPtr; VAR quitFlag: Boolean;
- callbackPtr: Ptr) : Boolean
-
- The paramBlock parameter points to the catalog information parameter block
- record (as returned by the File Manager function PBGetCatInfo) of the alias
- match. The Alias Manager sets this parameter to NIL if it is calling the
- function to give it the chance to terminate the search. (Do not use this
- pointer without checking for NIL.) Your filter function sets the quitFlag
- parameter to terminate the search.
-
- The callbackPtr parameter is the same as the SelectAlias input parameter
- callbackPtr. This parameter allows your filter function to access your global
- or local data.
-
-
- The alias parameter points to the alias record to be resolved and, if
- necessary, updated.
-
- After the alias is resolved to a single target, the target parameter receives
- the FSSpec for the target.
-
- If it updates the alias record, SelectAlias sets the wasChanged parameter to
- TRUE. Otherwise, it sets it to FALSE. If the function returns an error code, it
- sets wasChanged to FALSE.
-
- The filterProc parameter points to your application’s optional event-filtering
- function, to be called by ModalDialog. (SelectAlias calls ModalDialog when it
- displays the SelectAlias dialog box. For a description of the ModalDialog
- procedure, see the Dialog Manager chapter of Volume I.) The filterProc parameter
- is similar to the same parameter in the Standard File Package procedure
- SFPGetFile. The function pointed to by filterProc must be the same as the one
- you would pass directly to ModalDialog in its filterProc parameter, except that
- it takes an additional fourth argument, which is the callbackPtr parameter as
- passed to the SelectAlias routine. This option allows your filter function to
- access the value of callbackPtr to retrieve your data.
-
- The callbackPtr parameter contains whatever data you specify. Use this parameter
- to pass information to your filter function.
-
- Result codes
- fnfErr -43 No target was found
- paramErr -50 target, alias, or both are NIL, or the handle is corrupt
- userCanceledErr -128 The user canceled the operation
-
- You use the MatchAlias function to identify a list of possible matches and pass
- the list through a selection filter. The filter can pass more than one possible
- match.
-
- FUNCTION MatchAlias (fromFile: FSSpecPtr; rulesMask: LongInt; alias:
- AliasHandle;
- VAR aliasCount: Integer; aliasList: FSSpecListPtr; VAR
- needsUpdate: Boolean; aliasFilter: ProcPtr; callbackPtr:
- Ptr) : OSErr;
-
- MatchAlias resolves the alias record pointed to by the alias parameter and
- returns a list of FSSpec records in the structure pointed to by the aliasList
- parameter. If it identifies more than one possible target, MatchAlias places in
- the aliasCount parameter the number of candidates in aliasList. MatchAlias
- follows the rules specified by the rulesMask parameter. If it resolves the alias
- to an object other than the one stored in the alias record or if it returns a
- list of possible candidates, it sets the needsUpdate flag to TRUE. Your
- application is responsible for calling UpdateAlias if necessary after the target
- is identified.
-
- The fromFile parameter represents the starting point for a relative search. This
- parameter can be either NIL or a valid FSSpec record. If fromFile is NIL,
- MatchAlias does not perform a relative search.
-
- The rulesMask parameter specifies a set of rules to guide the resolution. Pass
- the sum of all of the rules you want to invoke.
-
- Constant Description
-
- kARMmountVol Automatically try to mount the target’s volume if it is not
- mounted. If this rule is not set, and if the target’s volume is
-
- not mounted, MatchAlias returns nsvErr.
-
- kARMmultVols Search all mounted volumes. The search begins with the volume on
-
- which the target resided when the record was created.
-
- kARMsearch Search quickly for the alias, using the fast-search algorithm.
-
- kARMsearchMore Search further, using the slow-search algorithm.
-
- The further search uses the File Manager function CatSearch to
- match criteria such as creation date, type, and creator.
- CatSearch is available only on HFS volumes. When searching MFS
- volumes or AppleShare volumes running older system software,
- MatchAlias performs a recursive, indexing search using creation
- date, type, and creator.
-
- If both kARMsearch and kARMsearchMore are set, MatchAlias
- performs a fast search followed by a slow search.
-
- The alias parameter points to the alias record to be resolved.
-
- Your application can specify a maximum number of possible matches by setting the
- aliasCount parameter. MatchAlias sets the aliasCount parameter to the number of
- entries in the list of possible matches.
-
- The aliasList parameter points to the array that holds the results of the
- search.
-
- If MatchAlias resolves the alias to a target whose key information is different,
- or if it returns a list of possible candidates, it sets the needsUpdate flag to
- TRUE. Otherwise, it sets it to FALSE.
-
- The aliasFilter parameter points to a filter function supplied by your
- application. The Alias Manager executes this function for each possible match
- that MatchAlias finds or after three seconds have elapsed without a match. Your
- filter function returns a Boolean value that determines whether the possible
- match is discarded (TRUE) or added to the list of possible targets (FALSE). It
- can also terminate the search. The function has three parameters.
-
- FUNCTION MyMatchAliasFilter (paramBlock: CInfoPBPtr; VAR quitFlag: Boolean;
- callbackPtr: Ptr): Boolean
- The paramBlock parameter points to the catalog information parameter block
-
- record (as returned by the File Manager function PBGetCatInfo) of the alias
- match. The Alias Manager sets this parameter to NIL if it is calling the
- function to give it the chance to terminate the search. (Do not use this
- pointer without checking for NIL.) Your filter function sets the quitFlag
- parameter to terminate the search.
-
- The callbackPtr parameter is the same as the MatchAlias input parameter
- callbackPtr. This parameter allows your filter function to access your global
-
- or local data.
-
-
- The callbackPtr parameter contains whatever data you specify. Use this
- parameter to pass information to your filter function.
-
- Result codes
- nsvErr -35 The volume is not mounted
- fnfErr -43 No target was found
- paramErr -50 target, alias, or both are NIL, or the handle is corrupt
- userCanceledErr -128 The user canceled the operation
-
-
- You can use the GetAliasInfo function to read information from an alias record.
-
- FUNCTION GetAliasInfo (alias: AliasHandle; index: AliasInfoType; VAR theString:
- Str63 ) : OSErr;
-
- GetAliasInfo retrieves the information specified by the index parameter from the
- record pointed to by the alias parameter and places it in the parameter
- theString.
-
- The alias parameter points to the alias record to be read.
-
- The index parameter specifies the kind of information to be retrieved. If index
- is a positive integer, GetAliasInfo retrieves the parent folder that has the
- same hierarchical level as the index parameter. You can therefore assemble the
- names of the target and all of its parent folders by making repeated calls to
- GetAliasInfo with incrementing index values, starting with a value of 0. When
- index is greater than the hierarchical level of the root, GetAliasInfo returns
- an empty string. You can also set index to one of these five values:
-
- Constant Value Description
- asiZoneName -3 If the record represents an object on an AppleShare volume,
-
- retrieve the server’s zone name. Otherwise, return an empty
- string.
-
- asiServerName -2 If the record represents an object on an AppleShare volume,
-
- retrieve server name. Otherwise, return an empty string.
-
- asiVolumeName -1 Return the name of the volume on which the represented
- object resides.
-
- asiAliasName 0 Return the name of the object represented by the record.
-
- asiParentName 1 Return the name of the parent folder of the object
- represented by the record. If the object is a volume,
- return the volume name.
-
- GetAliasInfo places the requested information in the parameter theString.
-
- GetAliasInfo returns the information stored in the alias record, which might not
- be current.
-
- Result codes
- paramErr -50 alias, theString, or both are NIL; the index is less
- than asiZoneName; or the handle is corrupt
- _______________________________________________________________________________
-
- æKY Summary…of…the…Alias…Manager
- æC »SUMMARY OF THE ALIAS MANAGER Alias Manager
- _______________________________________________________________________________
-
- The following cards summarize the constants, data types, and routines for the
- Alias Manager.
- _______________________________________________________________________________
-
- æKY Alias…Constants
- æC »Constants Alias Manager
- _______________________________________________________________________________
-
- CONST
- rAliasType = 'alis'; {resource type for saved alias records}
-
- {rulesMask for MatchAlias}
- kARMmountVol = $0001; {mount the volume automatically}
- kARMmultVols = $0008; {search on multiple volumes}
- kARMsearch = $0100; {search quickly}
- kARMsearchMore = $0200; {search further}
-
- {index values for GetAliasInfo}
- asiZoneName = -3;
- asiServerName = -2;
- asiVolumeName = -1;
- asiAliasName = 0;
- asiParentName = 1;
- _______________________________________________________________________________
-
- æKY Alias…Data…Types
- æC »Data Types Alias Manager
- _______________________________________________________________________________
-
- TYPE
- FSSpecArrayPtr = ^FSSpecArray;
- FSSpecArray = ARRAY[0..0] OF FSSpec;
-
- AliasHandle = ^AliasPtr;
- AliasPtr = ^AliasRecord;
- AliasRecord =
- RECORD
- userType: OSType;
- aliasSize: Integer;
- {variable-length private data}
- END;
- AliasInfoType = Integer;
- _______________________________________________________________________________
-
- æKY Alias…Routines
- æC »Routines Alias Manager
- _______________________________________________________________________________
-
- Creating and Updating Records
-
- FUNCTION NewAlias (fromFile,target: FSSpecPtr; VAR alias: AliasHandle) : OSErr;
- FUNCTION UpdateAlias (fromFile,target: FSSpecPtr; alias: AliasHandle; VAR
- wasChanged: Boolean) : OSErr;
-
- Resolving and Reading Records
-
- FUNCTION ResolveAlias (fromFile: FSSpecPtr; alias: AliasHandle; VAR target:
- FSSpec; VAR wasChanged: Boolean) : OSErr;
- FUNCTION SelectAlias (fromFile: FSSpecPtr; fileTypeName: Str31; aliasFilter:
- ProcPtr; alias: AliasHandle; VAR target: FSSpec; VAR
- wasChanged: Boolean; filterProc: ProcPtr; callbackPtr:
- Ptr)
- : OSErr;
- FUNCTION MatchAlias (fromFile: FSSpecPtr; rulesMask: LongInt; alias:
- AliasHandle;
- VAR aliasCount: Integer; aliasList: FSSpecListPtr; VAR
- needsUpdate: Boolean; aliasFilter: ProcPtr; callbackPtr:
- Ptr) : OSErr;
- FUNCTION GetAliasInfo (alias: AliasHandle; index: AliasInfoType; VAR theString:
- Str63; ) : OSErr;
- _______________________________________________________________________________
-
- æKY Alias…Result…Codes
- æC »Result Codes Alias Manager
- _______________________________________________________________________________
-
- nsvErr -35 The volume is not mounted
- fnfErr -43 No target was found
- paramErr -50 One or more parameters is NIL, or a handle is corrupt
- userCanceledErr -128 The user canceled the operation
- _______________________________________________________________________________
-
- æKY Assembly-Language…Information…for…Alias
- æC »Assembly-Language Information Alias Manager
- _______________________________________________________________________________
-
- Constants
-
- ;Resource type for alias records
- rAliasType .EQU 'alis'
-
- ;rulesMask for MatchAlias
- kARMmountVol .EQU $00000001; {mount the volume automatically}
- kARMmultVols .EQU $00000008; {search on multiple volumes}
- kARMsearch .EQU $00000100; {search quickly}
- kARMsearchMore .EQU $00000200; {search further}
-
- ;GetAliasInfo request types
- asiZoneName .EQU -3 ;get zone name
- asiServerName .EQU -2 ;get server name
- asiVolumeName .EQU -1 ;get volume name
- asiAliasName .EQU 0 ;get object name
- asiParentName .EQU 1 ;get parent folder name
-
- Alias Record Data Structure
- userType 4 bytes file type of target file
- aliasSize 2 bytes size of record in bytes
- {variable-length private data}
-
-
- _______________________________________________________________________________
-
-
- æKY AppleDesktopBus
- æC
- THE APPLE DESKTOP BUS
- _______________________________________________________________________________
-
- About…The…AppleDesktopBus…Chapter
- About…the…Apple…Desktop…Bus
- ADB…Manager…Routines
- Writing…ADB…Device…Drivers
- Summary…of…the…ADB
- _______________________________________________________________________________
-
-
-
- æKY About…The…AppleDesktopBus…Chapter
- æC »ABOUT THIS CHAPTER AppleDesktopBus
- _______________________________________________________________________________
-
- This chapter tells you how to accomplish low-level communication with peripheral
- devices that are connected to the Apple Desktop Bus (ADB).
-
- Reader’s guide: The standard mouse and keyboard drivers automatically take
- care of all required ADB access functions. When the user
- manipulates the mouse or keyboard, the system calls the
- appropriate driver and the application never uses the ADB
- Manager. Hence you need the information in this chapter only
- if you are writing a special driver, such as a driver for a
- new user-input device.
-
- The ADB is a simple local-area network that connects low-speed input-only devices to
- the operating system. In the Macintosh II and Macintosh SE computers, the ADB is used
- to communicate with one or more keyboards, the mouse, and other user input devices.
-
- Keys located on multiple keyboards are distinguished by the keyboard event message,
- as described in the Toolbox Event Manager chapter.
-
- Note: An ADB, using the same operating protocols, is also part of the
- Apple IIgs computer.
-
- This chapter contains three principal sections:
-
- • a description of the Apple Desktop Bus and how it works
- • a description of the ADB Manager. This section of system ROM contains
- the routines that a driver must use to access devices connected to the ADB.
- • a discussion of the special requirements for drivers that support
- devices connected to the ADB
-
- You should already be familiar with
-
- • the hardware interface to the Apple Desktop Bus, described in the
- Macintosh Family Hardware Reference
- • events generated by ADB keyboard devices (described in the Toolbox
- Event Manager chapter) if your driver communicates with one or more
- keyboards
-
- _______________________________________________________________________________
-
-
- æKY About…the…Apple…Desktop…Bus
- æC »ABOUT THE APPLE DESKTOP BUS AppleDesktopBus
- _______________________________________________________________________________
-
- The Apple Desktop Bus connects up to 16 low-speed input-only devices to the Macintosh
- II or Macintosh SE computer. Each device can maintain up to four variable-size registers,
- whose contents can be read from or written to by the ADB network. Each register may
- contain from two to eight bytes. Two of the device registers have an assigned meaning
- and a standardized format: register 0, used for interrupt information, and register
- 3, containing the device’s identification number. The other two device registers have
- no assigned meaning, and may have different meanings for read and write operations.
-
- The system communicates with the Apple Desktop Bus through the system’s Versatile
- Interface Adapter chip (VIA). The VIA is described in the Macintosh Hardware chapter.
-
- Warning: The ADB does not support connecting a device while the computer
- is running. The result may be to reinitialize all devices on the
- bus without informing the system.
-
- The system always controls the bus. It issues commands to specific devices on the bus
- and they respond by accepting data, sending data, or changing their configuration.
- These commands are discussed below.
-
- Note: Devices connected to the ADB contain their own single-chip
- microprocessors, which handle both device routines and the
- ADB interface. If the system sends commands to a device with
- a duty cycle of more than 50%, the device’s microprocessor
- may become overloaded.
-
- _______________________________________________________________________________
-
- »Bus Commands
-
- Each bus command consists of a byte that the system sends to a device connected to
- the ADB. Applications may place bus commands on the network by calling the routine
- ADBOp, discussed under “ADB Manager Routines” later in this chapter. There are four
- bus commands; their bit layouts are shown in Figure 1. All other bit layouts are
- reserved.
-
- •••Refer to Figure 1.•••
-
- Figure 1–ADB Command Formats
-
- The individual commands are discussed below.
-
- Warning: Values of the low bytes of the ADB command formats other than
- those shown in Figure 1 are reserved, and should not be used.
-
- »SendReset
-
- The SendReset command forces a hardware reset of all devices connected to the ADB.
- Such a reset clears all pending device actions and places the devices in their startup
- state. All devices are able to accept new ADB commands and user inputs immediately
- thereafter. All devices ignore the high-order four bits of the SendReset command.
-
- »Flush
-
- The Flush command flushes data from the single device specified by the network address
- in its high-order four bits. Network addresses are discussed below, under “Device
- Addressing”. It purges any pending user inputs and make the device ready to accept
- new commands and input data.
-
- »Listen
-
- The Listen command is used to send instructions to devices connected to the ADB. It
- transfers data from a buffer in system RAM to a register in the device specified by
- the network address in its high-order four bits. The device register is specified by
- the low-order two bits of the Listen command.
-
- »Talk
-
- The Talk command is used to fetch user inputs from devices connected to the ADB. It
- is the complement of the Listen command. It transfers data from a register in the
- device specified by the network address in its high-order four bits to a buffer in
- system RAM. The device register is specified by the low-order two bits of the Talk
- command.
-
- _______________________________________________________________________________
-
- »Device Registers
-
- Each device connected to the ADB contains four registers, each of which may store
- from two to eight bytes of data. Each register is identified by the value of the
- low-order two bits in a Listen or Talk command. Registers 0 and 3 have dedicated
- functions; registers 1 and 2 are used for purposes specific to each device, and need
- not be present in a device.
-
- Note: ADB device registers are virtual registers; they need not be
- implemented physically. The device firmware must only respond
- to register commands as if a register were present.
-
- »Register 0
-
- Device register 0 is reserved for input data. If the device has user-input data to be
- fetched, it places the data in register 0 and requests service. It continues to
- request service until the system retrieves its data. The system responds to data-input
- requests with the following polling sequence:
-
- • It generates a Talk command for register 0 in each device connected
- to the ADB.
- • If the device has data to send, it responds. The system does not
- poll the next device until the data is exhausted.
- • If the device has no data to send, or if its data is exhausted, the
- VIA generates an interrupt. The system then polls the next device.
- • This process continues until no devices request service.
-
- »Register 3
-
- Device register 3 is reserved for device identification data and operating flags.
- Application programs may set this data with Listen commands and read it with Talk
- commands. Register 3 stores 16 bits, divided into the fields shown in Figure 2.
-
- •••Refer to Figure 2.•••
-
- Figure 2–Format of Device Register 3
-
- Except for commands that contain certain reserved device handler ID values
- (listed below), every command to register 3 changes the entire register contents.
- Hence to change part of the register, you should first fetch its current contents
- with a Talk command and then send it an updated value with Listen. You can change
- part of the contents of register 3 by using special device handler ID values, as
- described below.
-
- The device handler ID field indicates the device’s type. With certain devices, an
- application can change the device’s mode of operation by sending it a new ID value.
- If the device supports the new mode, it stores the new value in this field.
-
- Warning: You are assigned handler IDs by Apple Software Licensing, so
- they do not conflict with the values of other devices that may
- be connected to the ADB at the same time.
-
- When certain reserved values are sent to the device handler ID field by a Listen
- command, they are not stored in the field; instead, they cause specific device actions.
- Hence these values cannot be used as device ID values. They are the following:
-
- Value Action
-
- $00 Change bits 8–13 of register 3 to match the rest of the command;
- leave Device Handler ID value unchanged.
- $FD Change Device Address to match bits 8–11 if the device activator
- has been depressed; leave Device Handler ID value and flags unchanged.
- $FE Change Device Address to match bits 8–11 if the result produces no
- address duplication on the bus; leave Device Handler ID value and
- flags unchanged.
- $FF Initiate device self-test. If self-test succeeds, leave register 3
- unchanged; if self-test fails, clear Device Handler ID field to $00.
-
- Other Device Handler ID values may be stored in the field.
-
- Note: Device Handler ID values below $20 are reserved by Apple.
-
- The Device Address field indicates the device’s location within the 16 possible
- device locations of the ADB. An application may change its value with a Listen command.
- When this field is interrogated with a Talk command, it returns a random value. This
- helps you separate multiple devices that have the same ADB address; for further
- information, see “Device Addressing”, below.
-
- The Service Request Enable bit is set by the device to request an interrupt poll.
-
- _______________________________________________________________________________
-
- »Device Addressing
-
- There are 16 possible direct addresses, $00–$0F, for devices connected to the ADB.
- However, it is possible to connect more than one device to an address; this might
- happen, for example, in a system with two alternate keyboards.
-
- When several devices share a single ADB address, but there are free addresses available
- in the net, the system will automatically reassign addresses until they are all
- different. It will do this every time the ADB Manager is initialized or reinitialized.
- To find out a device’s new address, use the calls GetIndADB or GetADBInfo, described
- later in this chapter.
-
- _______________________________________________________________________________
-
- »Standard ADB Device Drivers
-
- The Macintosh II and Macintosh SE systems contain two standard ADB drivers:
-
- • the mouse driver, which supports the ADB mouse. The Apple mouse
- has an original ADB address of 3.
- • the universal keyboard driver, which supports all Apple ADB keyboards.
- The Apple keyboard has an original ADB address of 2, with a Device
- Handler ID of 1 for the Macintosh II keyboard and 2 for the Apple
- Extended Keyboard. These keyboards are described in the Toolbox
- Event Manager chapter.
-
- These drivers reside in the system ROM. In addition, ADB address 0 is reserved for
- the ADB chip itself. You can change the ADB addresses of the mouse or keyboard, as
- described above under “Device Registers,” but Apple does not recommend doing so.
-
- Assembly-language note: The ADB address of the keyboard on which the
- last-typed character was entered is now stored
- in the global variable KbdLast. The type of the
- keyboard on which the last-typed character was
- entered is stored in the global variable KbdType.
- The value of KbdType is the Device Handler ID
- value in Register 3 of the device; values below
- $20 are reserved by Apple.
-
- The requirements for writing new ADB device drivers are discussed later in this
- chapter.
-
- _______________________________________________________________________________
-
-
- æKY ADB…Manager…Routines
- æC »ADB MANAGER ROUTINES AppleDesktopBus
- _______________________________________________________________________________
-
- The ADB Manager consists of six routines located in the 256K ROM. You would use them
- only if you needed to access bus devices directly or communicate with a special
- device.
-
- Some of these routines access and update information in the ADB device table, a
- structure placed in the system heap by ROM code during system startup. It lists for
- each device the device’s type, its original ADB address, its current ADB address, the
- address of the routine that services the device, and the address of the area in RAM
- used for temporary data storage by its driver. The ADB device table is accessible
- only through ADB Manager routines.
-
- PROCEDURE ADBReInit;
-
- Trap macro _ADBReInit
-
- ADBReInit reinitializes the entire Apple Desktop Bus. It clears the ADB device table
- to zeros and places a SendReset command on the bus to reset all devices to their
- original addresses. ADBReInit has no parameters.
-
- Because it does not deallocate ADB resources on the system heap, ADBReInit should not
- be used for routine bus initialization. Apple strongly recommends against adding
- devices while the system is running; therefore, you should never call ADBReInit.
-
- ADBReInit also calls a routine pointed to by the low memory global JADBProc
- at the beginning and end of its execution. You can insert your own
- preprocessing/postprocessing routine by changing the value of JADBProc; ADBReInit
- conditions it by setting D0 to 0 for preprocessing and to 1 for postprocessing. Your
- procedure must restore the value of D0 and branch to the original value of JADBProc
- on exit. JADBProc should be used to de-allocate memory used by the driver (see
- MacDTS Sample Code “TbltDrvr” for an example), and then it should chain to the procedure
- originally found in JADBProc.
-
- The complete ADBReInit sequence is therefore the following:
-
- • JSR to JADBProc with D0 set to 0
- • reinitialize the Apple Desktop Bus
- • clear the ADB device table
- • JSR to JADBProc with D0 set to 1
-
- FUNCTION ADBOp (data: Ptr; compRout: ProcPtr; buffer: Ptr;
- commandNum: INTEGER) : OSErr;
-
- Trap macro _ADBOp
-
- On entry: A0: pointer to parameter block
- D0: commandNum (byte)
-
- Parameter block
- --> 0 buffer pointer
- --> 4 compRout pointer
- --> 8 data pointer
-
- On exit: D0: result code (byte)
-
- The completion routine pointed to by compRout will be passed the following parameters
- on entry:
-
- D0: commandNum (byte)
- A0: pointer to buffer, data stored as a Pascal string (maximum
- 8 bytes data preceded by one length byte)
- A1: pointer to completion routine (compRout)
- A2: pointer to optional data area (data)
-
- ADBOp transmits over the bus the command byte whose value is given by commandNum. The
- structure of the command byte is given earlier in Figure 1. ADBOp executes only when
- the ADB is otherwise idle; otherwise it is held in a command queue. It returns an
- error if the command queue is full. The length of the data buffer pointed to by
- buffer is contained in its first byte, like a Pascal string. The optional data area
- pointed to by data is for local storage by the completion routine pointed to by
- compRout. ADBop should be used sparingly; it is not intended for polling a device.
- The host automatically polls devices with data to deliver.
-
- Result codes noErr No error
- –1 Unsuccessful completion
-
- FUNCTION CountADBs: INTEGER;
-
- Trap macro _CountADBs
-
- On exit: D0: number of devices (byte)
-
- CountADBs returns a value representing the number of devices connected to the ADB by
- counting the number of entries in the device table. It has no arguments and returns
- no error codes.
-
- FUNCTION GetIndADB (VAR info: ADBDataBlock;
- devTableIndex: INTEGER) : ADBAddress;
-
- Trap macro _GetIndADB
-
- On entry: A0: pointer to parameter block
- D0: entry index number; range = 1..CountADBs (byte)
-
- Parameter block
- <-- 0 device type byte (handler ID)
- <-- 1 original ADB address byte
- <-- 2 service routine address pointer (compRout)
- <-- 6 data area address pointer (data)
-
- On exit: D0: positive value: current ADB address (byte)
- negative value: error code (byte)
-
- GetIndADB returns information from the ADB device table entry whose index number is
- given by devTableIndex. ADBDataBlock has this form:
-
- TYPE ADBDataBlock =
- PACKED RECORD
- devType: SignedByte; {device type (handler ID)}
- origADBAddr: SignedByte; {original ADB address}
- dbServiceRtPtr: Ptr; {service routine address (compRout)}
- dbDataAreaAddr: Ptr {data area address (data)}
- END;
-
- GetIndADB returns the current ADB address of the device. If it is unable to complete
- execution successfully, GetIndADB returns a negative value.
-
- FUNCTION GetADBInfo (VAR info: ADBDataBlock; ADBAddr: ADBAddress) : OsErr;
-
- Trap macro _GetADBInfo
-
- On entry: A0: pointer to parameter block
- D0: ADB address of the device (byte)
-
- Parameter block
- <-- 0 device handler ID byte
- <-- 1 original ADB address byte
- <-- 2 service routine address pointer (compRout)
- <-- 6 data area address pointer (data)
-
- On exit: D0: result code (byte)
-
- GetADBInfo returns information from the ADB device table entry of the device whose
- ADB address is given by ABDAddr. The structure of ADBDataBlock is given above under
- “GetIndADB”.
-
- Result codes noErr No error
-
- FUNCTION SetADBInfo (VAR info: ADBSetInfoBlock; ADBAddr: ADBAddress) : OsErr;
-
- Trap macro _SetADBInfo
-
- On entry: A0: pointer to parameter block
- D0: ADB address of the device (byte)
-
- Parameter block
- --> 0 service routine address pointer (compRout)
- --> 4 data area address pointer (data)
-
- On exit: D0: result code (byte)
-
- SetADBInfo sets the service routine address and the data area address in the ADB
- device table entry for the device whose ADB address is given by ABDAddr. ADBSetInfoBlock
- has this form:
-
- TYPE ADBSetInfoBlock =
- RECORD
- siServiceRtPtr: Ptr; {service routine address (compRout)}
- siDataAreaAddr: Ptr {data area address (data)}
- END;
-
- Result codes noErr No error
-
- Warning: You should send a Flush command to the device after calling it
- with SetADBInfo, to prevent it sending old data to the new data
- area address.
-
- _______________________________________________________________________________
-
-
- æKY Writing…ADB…Device…Drivers
- æC »WRITING ADB DEVICE DRIVERS AppleDesktopBus
- _______________________________________________________________________________
-
- Drivers for devices connected to the ADB have the following special requirements:
-
- • Each ADB device driver must reside in a resource of type 'ADBS'.
- (An example 'ADBS' resource is available in MacDTS Sample Code
- “TbltDrvr.”) This type has two sections: initialization and driver code.
- • The initialization section of each ADB device driver must support the
- installation procedure described below.
-
- When the system calls an ADB device driver, it passes it the following values:
-
- • Register A0 points to the data buffer, which is formatted as a
- Pascal string (buffer).
- • Register A1 points to the driver’s completion routine (compRout).
- • Register A2 points to the optional data area (data).
- • Register D0 contains the ADB command that resulted in the driver
- being called (commandNum).
-
- The ADB driver should handle the ADB command passed to it and store any resulting
- input data by an appropriate action, such as by posting an event or moving the cursor.
-
- Note: Events posted from keyboards connected to the ADB now have an
- expanded structure. For more information, see the Toolbox Event
- Manager chapter.
-
- _______________________________________________________________________________
-
- »Installing an ADB Driver
-
- The Start Manager (described in this volume) finds all the ADB devices connected to
- the system and places their device types and ADB addresses in the ADB device table.
- It then calls the initialization section of each ADB device driver by executing the
- initialization code in its 'ADBS' resource.
-
- As a minimum, the initialization section of each ADB device driver must do the following:
-
- • The driver must allocate all the memory required by the driver code
- in one or more nonrelocatable blocks in the system heap area.
- • The driver must install its own preprocessing/postprocessing routine
- (if any) as described above under “ADBReInit”.
- • Finally, the driver must initialize the service routine address and
- data area address of its entry in the ADB device table, using SetADBInfo.
-
- _______________________________________________________________________________
-
-
- æKY Summary…of…the…ADB
- æC »SUMMARY OF THE ADB MANAGER AppleDesktopBus
- _______________________________________________________________________________
-
- Data Types
-
- TYPE
- ADBDataBlock =
- PACKED RECORD
- devType: SignedByte; {Handler ID}
- origADBAddr: SignedByte; {original ADB address}
- dbServiceRtPtr: Ptr; {service routine address (compRout)}
- dbDataAreaAddr: Ptr {data area address (area)}
- END;
-
- ADBSetInfoBlock =
- RECORD
- siServiceRtPtr: Ptr; {service routine address}
- siDataAreaAddr: Ptr {data area address}
- END;
-
- _______________________________________________________________________________
-
- Routines
-
- Initializing the ADB Manager
-
- PROCEDURE ADBReInit;
-
- Communicating Through the ADB
-
- FUNCTION ADBOp (data: Ptr; compRout: ProcPtr; buffer: Ptr;
- commandNum: INTEGER) : OSErr;
-
- Getting ADB Device Information
-
- FUNCTION CountADBs: INTEGER;
- FUNCTION GetIndADB (VAR info: ADBDataBlock;
- devTableIndex: INTEGER) : ADBAddress;
- FUNCTION GetADBInfo (VAR info: ADBDataBlock; ADBAddr: ADBAddress) : OsErr;
-
- Setting ADB Device Information
-
- FUNCTION SetADBInfo (VAR info: ADBSetInfoBlock; ADBAddr: ADBAddress) : OsErr;
-
- _______________________________________________________________________________
-
- Assembly-Language Information
-
- Variables
-
- JADBProc Pointer to ADBReInit preprocessing/postprocessing routine
- KbdLast ADB address of the keyboard last used (byte)
- KbdType Keyboard type of the keyboard last used (byte)
-
- Routines
-
- Trap macro On entry On Exit
-
- _ADBReInit
-
- _ADBOp A0: pointer to parameter block D0: result code (byte)
- buffer (pointer)
- compRout (pointer)
- data (pointer)
- D0: commandNum (byte)
-
- _CountADBs D0: result code (byte)
-
- _GetIndADB A0: pointer to parameter block D0: positive value:
- device type (byte) current ADB
- original ADB address (byte) address (byte)
- service routine address (pointer) negative value:
- data area address (pointer) error code (byte)
- D0: entry index number;
- range = 1..CountADBs (byte)
-
- _GetADBInfo A0: pointer to parameter block D0: result code (byte)
- device handler ID (byte)
- original ADB address (byte)
- service routine address (pointer)
- data area address (pointer)
- D0: current ADB address of the device (byte)
-
- _SetADBInfo A0: pointer to parameter block D0: result code (byte)
- service routine address (pointer)
- data area address (pointer)
- D0: current ADB address of the device (byte)
-
- Further Reference:
- _______________________________________________________________________________
- Toolbox Event Manager
- Technical Note #143, Don’t Call ADBReInit on the SE with System 4.1
- Technical Note #160, Key Mapping
- Technical Note #206, Space Aliens Ate My Mouse
- “Macintosh Family Hardware Reference”
-
-
- æKY AppleTalkManager
- æC
- _______________________________________________________________________________
-
- APPLETALK MANAGER
- _______________________________________________________________________________
-
- About…the…AppleTalk…Chapter
- About…the…AppleTalk…Manager
- Changes…to…the…AppleTalk…Manager
- AppleTalk…Protocols
- AppleTalk…Device…Drivers,…'adev'…Files,…and…the…LAP…Manager
- Using…the…AppleTalk…Manager
- Determining…Whether…AppleTalk…Phase…2…Drivers…Are…Present
- Determining…Which…AppleTalk…Protocol…to…Use
- The….MPP…Driver
- Getting…Information…About…the….MPP…Driver
- A…New…NBP…Wildcard…Character
- The…LAP…Manager
- The…AppleTalk…Transition…Queue
- Adding…and…Removing…AppleTalk…Transition…Queue…Entries
- Sending…Messages…to…the…AppleTalk…Transition…Queue
- How…the…AppleTalk…Manager…Calls…Your…Transition…Queue…Routine
- The…LAP…Manager…802.2…Protocol
- Attaching…and…Detaching…802.2…Protocol…Handlers
- AppleTalk…Data…Stream…Protocol…(ADSP)
- Using…ADSP
- The…ADSP…Connection…Control…Block
- The….DSP…Parameter…Block
- Opening…and…Maintaining…an…ADSP…Connection
- Creating…and…Using…a…Connection…Listener
- Writing…a…User…Routine…For…Connection…Events
- DSP…Driver…Commands
- Establishing…and…Terminating…an…ADSP…Connection
- Establishing…and…Terminating…an…ADSP…Connection…Listener
- Maintaining…an…ADSP…Connection
- The….ATP…Driver
- Canceling…All…Calls…to…the…ATPGetRequest…Function
- Setting…the…Timeout…Value…For…the…ATP…Release…Timer
- The….XPP…Driver
- Using…the….XPP…Driver…to…Obtain…Zone…Information
- XPP…Driver…Routines
- The….ENET…Driver
- Changing…the…Ethernet…Hardware…Address
- Opening…the….ENET…Driver
- Using…a…Write-Data…Structure…to…Transmit…Ethernet…Data
- Using…the…Default…Ethernet…Protocol…Handler…to…Read…Data
- Using…Your…Own…Ethernet…Protocol…Handler…to…Read…Data
- How…the….ENET…Driver…Calls…Your…Protocol…Handler
- How…Your…Protocol…Handler…Calls…the….ENET…Driver
- ENET…Driver…Routines
- Attaching…and…Detaching…an…Ethernet…Protocol…Handler
- Writing…and…Reading…Packets…Using…the…Default…Protocol…Handler
- Adding…and…Removing…Ethernet…Multicast…Addresses
- Summary…of…the…AppleTalk…Manager
- AppleTalk…Constants
- AppleTalk…Data…Types
- AppleTalk…Routines
- AppleTalk…Result…codes
- Assembly-language…Information…for…AppleTalk
- _______________________________________________________________________________
-
-
-
- æKY About…the…AppleTalk…Chapter
- æC »ABOUT THIS CHAPTER AppleTalk Manager
- _______________________________________________________________________________
-
- AppleTalk is a communication network system including personal computer
- workstations, computers acting as file servers and print servers, printers, and
- a variety of types of communication hardware and software. The AppleTalk Manager
- provides an interface to this communication network system for applications
- running on Macintosh computers. This chapter describes the changes to the
- AppleTalk Manager introduced as AppleTalk Phase 2 and included with system
- software version 7.0. This chapter supplements the information in the AppleTalk
- Manager chapters of Inside Macintosh, Volumes II and V.
-
- This chapter describes
- • new routines for the .MPP, .ATP, and .XPP device drivers
-
- • a new wildcard character for use with the Name-Binding Protocol
-
- • a new system queue, called the AppleTalk Transition Queue
-
- • a new set of operating system utilities, collectively called the LAP
- Manager.
-
- • the .ENET driver and the routines your application can use to control
- this driver
-
- • the application interface routines provided by a new AppleTalk protocol,
- the AppleTalk Data Stream Protocol
-
- Together with the AppleTalk Manager chapters of Volumes II and V, this chapter
- describes the routines that your application can use to send and receive
- information within an AppleTalk network system . Because the AppleTalk network
- system includes both hardware and software, and because the software includes
- not only the AppleTalk Manager but file servers, print servers, internet
- routers, drivers for circuit cards, and so forth, the information in Inside
- Macintosh constitutes only a small part of the body of literature documenting
- AppleTalk.
-
- For a detailed description of AppleTalk protocols, see Inside AppleTalk. For a
- complete description of the LAP Manager, EtherTalk, and alternate AppleTalk
- connections, see the AppleTalk Connections Programmer’s Guide. To learn how to
- install and operate an AppleTalk internet, see the AppleTalk Internet Router
- Administrator’s Guide and the AppleTalk Phase 2 Introduction and Upgrade Guide.
- For an introduction to the hardware and software of an entire AppleTalk network,
- see Understanding Computer Networks and the AppleTalk Network System Overview.
- For information on designing circuit cards and device drivers for Macintosh
- computers, see Designing Cards and Drivers for the Macintosh Family.
-
- You can install the Phase 2 versions of the AppleTalk drivers on any Macintosh
- computer other than the Macintosh XL, Macintosh 128K, Macintosh 512K, and
- Macintosh 512K enhanced computers. If you want to provide AppleTalk Phase 2
- device drivers with your product, you must obtain a license from Apple Software
- Licensing.
-
- _______________________________________________________________________________
-
- æKY About…the…AppleTalk…Manager
- æC »ABOUT THE APPLETALK MANAGER AppleTalk Manager
- _______________________________________________________________________________
-
- The AppleTalk Manager includes a number of protocols that are implemented in
- various device drivers. The AppleTalk Manager also includes the LAP Manager,
- which interfaces the AppleTalk data links to the AppleTalk protocols; and
- hardware device drivers for specific networks. The AppleTalk data links are
- contained in files of type 'adev', sometimes referred to as 'adev' files. This
- section lists the new features that have been introduced as AppleTalk Phase 2,
- describes the organization of the AppleTalk Manager, and briefly discusses what
- each component of the AppleTalk Manager does.
-
-
- _______________________________________________________________________________
-
- æKY Changes…to…the…AppleTalk…Manager
- æC »Changes to the AppleTalk Manager AppleTalk Manager
- _______________________________________________________________________________
-
- The features that have been introduced as AppleTalk Phase 2 include
-
- • a new .MPP driver function that returns information about the .MPP driver
-
- • a new protocol, the AppleTalk Data Stream Protocol (ADSP), which provides
- full-duplex data stream communications for use by applications; see
- “AppleTalk Data Stream Protocol”
-
- • improvements to the Zone Information Protocol (ZIP) that allow a single
- network (other than LocalTalk) to contain more than one zone; see
- “Obtaining Zone Information.”
-
- • new functions for the .XPP device driver that provide information from
- ZIP about zones; see “The .XPP Driver”
-
- • a new Name Binding Protocol (NBP) wildcard character that can substitute
- for one or more characters in AppleTalk names; see “A New NBP Wildcard
- Character”
-
- • the AppleTalk Transition Queue, an operating system queue that can notify
- your application each time an AppleTalk driver is opened or closed, or
- certain other transitions occur; see “The AppleTalk Transition Queue”
-
- • the LAP Manager, a new set of operating system utilities that provide a
- standard interface between the AppleTalk protocols and the data links
- used by Appletalk, such as EtherTalk, LocalTalk, and TokenTalk; see “The
- LAP Manager”
-
- • the .ENET driver, an Ethernet driver for the EtherTalk NuBus card that is
- manufactured by Apple Computer, Inc.; see “The .ENET Driver”
-
- • an implementation of the IEEE 802.2 protocol, which allows you to attach
- and detach your own protocol handlers for EtherTalk and TokenTalk data
- packets; see “The LAP Manager 802.2 Protocol”
-
- • new .ATP driver functions that allow you to set a value for the .ATP
- release timer and to cancel all pending asynchronous calls to the
- ATPGetRequest function for a specific socket; see “The .ATP Driver”
- _______________________________________________________________________________
-
- æKY AppleTalk…Protocols
- æC »AppleTalk Protocols AppleTalk Manager
- _______________________________________________________________________________
-
- The AppleTalk Manager comprises the following protocols:
-
- • LocalTalk Link Access Protocol (LLAP)
- • Datagram Delivery Protocol (DDP)
- • Routing Table Maintenance Protocol (RTMP)
- • AppleTalk Transaction Protocol (ATP)
- • Name-Binding Protocol (NBP)
- • AppleTalk Echo Protocol (AEP)
- • Zone Information Protocol (ZIP)
- • AppleTalk Session Protocol (ASP)
- • AppleTalk Data Stream Protocol (ADSP)
- • AppleTalk Filing Protocol (AFP)
-
- The EtherTalk Link Access Protocol, TokenTalk Link Access Protocol, and other
- Link Access Protocols provide interfaces between the AppleTalk Manager and the
- different types of data link hardware used by AppleTalk.
-
- Note: The LocalTalk Link Access Protocol (LLAP) was originally called the
- AppleTalk Link Access Protocol (ALAP). It has been renamed to avoid confusion
- with the EtherTalk Link Access Protocol and other link access protocols.
-
- Figure 29-1 shows the relationships among the various AppleTalk protocols. A
- line going from a protocol to another protocol above or below it in the figure
- indicates that the upper protocol is a client of the lower protocol; that is,
- the upper protocol uses services provided by the lower protocol in order to
- carry out some functions.
-
- Note: The various AppleTalk protocols are sets of rules, not computer programs,
- and so can be implemented in many different ways on many different systems. All
- of the AppleTalk protocol functions that you can address or control from a
- Macintosh application are implemented as Macintosh device drivers or managers.
- Many other features of these protocols are implemented in software located only
- on internet routers that are not used to run general applications. Some parts of
- protocols are implemented by server software such as file servers and print
- servers. Therefore, when this chapter refers to a protocol as “doing” or
- “controlling” something, you should understand the statement to mean that some
- program that implements the protocol actually carries out the operation.
-
- ø 29.1 AppleTalk Protocols
-
- A link access protocol controls the access of the node to the network hardware,
- making it possible for many nodes to share the same communication hardware. Each
- link access protocol assigns a node ID to the node and decodes the node
- addresses of messages it receives. A link access protocol provides node-to-node
- delivery of data packets. Examples of link access protocols include the
- LocalTalk Link Access Protocol, the EtherTalk Link Access Protocol, and the
- TokenTalk Link Access Protocol.
-
- Whereas earlier implementations of AppleTalk were restricted to one 16-bit
- network number per cable (that is, one network number for all nodes connected
- with no intervening routers) and 254 nodes per network number, AppleTalk Phase 2
- allows more than one network number for each cable (other than LocalTalk, which
- is still limited to one network number on a cable). Each node in a network other
- than LocalTalk must be specified by both its 16-bit network number and its 8-bit
- node ID. In principle, each cable (other than LocalTalk) can now have over 16
- million (224) nodes. In any specific implementation, the hardware or software
- might limit the network to fewer nodes.
-
- Note: Before the introduction of AppleTalk Phase 2, AppleTalk allowed only one
- network number per cable (that is, one network number for all nodes connected
- with no intervening routers), and the term network was used to include all of
- the nodes connected by a single cable. Under AppleTalk Phase 2, however, more
- than one network number can be assigned to a single cable. The term network is
- now sometimes used to refer to the collection of all the nodes that share a
- single network number, and is sometimes used in the older sense to refer to all
- nodes connected with no intervening routers. In the latter case, you could say
- that a single network can have a range of network numbers. Because of this
- ambiguity, it is best to avoid using the term network without modifiers.
-
- The Datagram Delivery Protocol provides socket-to-socket delivery of data
- packets within an AppleTalk internet. A DDP packet’s address includes the socket
- number, node ID, and network number. Application-interface routines for DDP are
- described in “Datagram Delivery Protocol” in the AppleTalk Manager chapter of
- Volume II.
-
- The Routing Table Maintenance Protocol is used by routers on an AppleTalk
- internet to determine how to forward a data packet to the network number to
- which it is addressed. The RTMP implementation on a router maintains a table,
- called a routing table, that specifies the shortest path to each possible
- destination network number. The AppleTalk protocol software in a workstation
- contains only a small part of RTMP, called the RTMP stub, that DDP uses to
- determine the network number (or range of network numbers) of the network cable
- to which the node is connected and the network number and node ID of one router
- on that network cable. There is no application interface to the RTMP stub.
-
- The AppleTalk Transaction Protocol provides loss-free communications by
- retransmitting any data packets that are lost. Although—as you can see from
- Figure 29-1—the AppleTalk Manager provides high-level protocols that are clients
- of ATP, many applications use ATP directly to transmit data over an AppleTalk
- internet. The application interface to ATP is described in the AppleTalk Manager
- chapter of Volume II. There are some enhancements to ATP in AppleTalk Phase 2,
- described in “Changes to the .ATP Driver” later in this chapter.
-
- The Name-Binding Protocol maintains a table that contains the internet address
- and name of each entity in the node that is visible to other entities on the
- internet. The internet address includes the socket number, node ID, and network
- number. The name consists of three fields: the object, type, and zone. The
- object and type are assigned by the entity itself and can be anything the user
- or application assigns. A zone is a logical grouping of a subset of the nodes on
- the internet. The zone field of the name is the zone in which the node resides.
-
- NBP also allows its clients to obtain the internet address of any
- network-visible entity in the internet by providing its name. NBP maps this name
- to an internet address, thus providing the link between the user-supplied name
- for an entity and the internet address that is used by DDP to send and receive
- data packets. The application interface to NBP is described in the AppleTalk
- Manager chapter of Volume II. There is one enhancement to NBP in AppleTalk Phase
- 2, described in “A New NBP Wildcard Character” later in this chapter.
-
- The AppleTalk Echo Protocol listens for special packets sent by other nodes and,
- when it receives such a packet, echoes it back to the sender. The AEP is used by
- some clients of DDP to determine whether another node (known to have AEP) can be
- accessed over the internet, and to determine how long it takes a packet to reach
- another node. There is no application interface to AEP.
-
- The Zone Information Protocol maintains a table in each router, called the zone
- information table, that lists the relationships between zone names and networks.
- In AppleTalk Phase 2, a network (other than LocalTalk) can contain more than one
- zone or a zone can contain more than one network. You can use .XPP driver
- routines to obtain information from ZIP; these routines are discussed in
- “Obtaining Zone Information” later in this chapter.
-
- The AppleTalk Session Protocol sets up and maintains sessions between a
- workstation and a server. A session consists of a logical (as opposed to
- physical) connection between two entities on the internet. ASP is a
- nonsymmetrical protocol; that is, only one of the two entities involved in the
- session (the workstation) can send commands; the other entity (the server) is
- restricted to responding to the commands. ASP is used by the AppleTalk Filing
- Protocol, for example, to allow a user to manipulate files on a file server. As
- long as the session is open, the workstation can request directory information,
- change file names, and so forth. The file server must respond to the
- workstation’s commands and cannot initiate any actions on its own. ASP is
- discussed in the AppleTalk Manager chapter of Volume V.
-
- The AppleTalk Data Stream Protocol appears to its clients to maintain an open
- pipeline between two entities on the internet. Either entity can write a stream
- of bytes to the pipeline, or read data bytes from the pipeline. ADSP is a
- symmetrical protocol; that is, the two clients at either end of the connection
- are equal and can perform exactly the same operations. ADSP is especially useful
- for exchanging information between two equal entities, as in a telephone
- communication network, or for sending or receiving a continuous stream of data,
- as required by a terminal emulation program, for example. Because ADSP is a
- client of DDP, the data is actually sent as data packets, allowing ADSP to
- correct errors in transmission in a way that would not be possible for a true
- data stream connection. Thus, ADSP retains many of the advantages of a
- transaction-based protocol while providing to its clients a full-duplex data
- stream. ADSP is discussed in the sections “Using ADSP” and “.DSP Driver
- Functions” later in this chapter.
-
- The AppleTalk Filing Protocol provides an interface between an application and a
- file server. AFP is a client of ASP, and is used to access AppleShare file
- servers on Macintosh computer workstations. When the user opens a session with
- an AppleShare file server over an internet, it appears to any application
- running on the workstation that uses File Manager routines as if the files on
- the file server were located on a disk drive connected to the workstation. The
- application interface to AFP is described in the AppleTalk Manager chapter of
- Volume V.
- _______________________________________________________________________________
-
- æKY AppleTalk…Device…Drivers,…'adev'…Files,…and…the…LAP…Manager
- æC »AppleTalk Device Drivers, 'adev' Files, and the LAP Manager AppleTalk Manager
- _______________________________________________________________________________
-
- A protocol is only a set of rules, not a computer program. The various AppleTalk
- protocols are implemented as Macintosh device drivers, including
-
- • the .MPP driver, which implements LLAP, DDP, NBP, AEP, and the RTMP stub
- • the .ATP driver, which implements ATP
- • the .XPP driver, which implements ASP and the workstation portions of ZIP
- and AFP
- • the .DSP driver, which implements ADSP
- • the .ENET driver, which implements Ethertalk
-
- AppleTalk can also include one or more 'adev' files. An 'adev' file has file
- type 'adev' and contains a link access protocol implementation for a network
- (ELAP for Ethernet, for example). The LAP Manager makes it possible for the user
- to select among 'adev' files by using the Network control panel to control which
- network is used for the node’s AppleTalk connection. The 'adev' file and LAP
- Manager work together with the Network control panel (Network cdev) file. When
- the user selects a connection from the Network control panel, the LAP Manager
- routes AppleTalk communications through the selected link access protocol and
- hence through the selected hardware.
-
- The AppleTalk device drivers, LAP Manager, and 'adev' files are shown in Figure
- As you can see from the figure, each device driver implements one or more
- AppleTalk protocols.
-
- ø 29.2 AppleTalk Device Drivers
-
- Figure 29-3 shows the interfaces between a general application on a Macintosh
- computer being used as an AppleTalk workstation and the AppleTalk protocols, the
- LAP Manager, and the Ethernet hardware device driver. The lines connecting the
- application to the various components of AppleTalk indicate which components
- have application interfaces. As discussed in the preceding section, “AppleTalk
- Protocols,” each application interface is described at least in part in this or
- another volume of Inside Macintosh.
-
- ø 29.3 AppleTalk Application Interfaces.
-
- _______________________________________________________________________________
-
- æKY Using…the…AppleTalk…Manager
- æC »USING THE APPLETALK MANAGER AppleTalk Manager
- _______________________________________________________________________________
-
- This section describes how to determine whether AppleTalk Phase 2 drivers are
- present and gives some advice on how to select the AppleTalk protocol that best
- servers your purposes. This section also describes how to use the features added
- to AppleTalk with Phase 2 and provides programming examples of the use of the
- .DSP driver and several other new AppleTalk features.
-
- _______________________________________________________________________________
-
- æKY Determining…Whether…AppleTalk…Phase…2…Drivers…Are…Present
- æC »Determining Whether AppleTalk Phase 2 Drivers Are Present AppleTalk Manager
- _______________________________________________________________________________
-
- Once the .MPP driver has been loaded into memory, you can use the Gestalt
- function to check the version of AppleTalk. The Gestalt function returns the
- version of the .MPP driver; if the version is greater than or equal to 53, then
- the .MPP driver supports AppleTalk Phase 2, and you can assume the other Phase 2
- drivers are present as well.
-
- Alternatively, you can call the SysEnvirons function as described in Chapter 1
- of Volume V. If the atDrvrVersNum field of the SysEnvRec record returned by this
- function is greater than or equal to 53, the .MPP driver supports AppleTalk
- Phase 2.
-
- _______________________________________________________________________________
-
- æKY Determining…Which…AppleTalk…Protocol…to…Use
- æC »Determining Which AppleTalk Protocol to Use AppleTalk Manager
- _______________________________________________________________________________
-
- AppleTalk offers a variety of communication protocols at a variety of levels.
- Your choice of protocol or protocols to use depends primarily on your needs, and
- can be influenced by your familiarity with network communications in general.
- You can write your own protocol handlers and call the low-level AppleTalk device
- drivers directly. However, if you are not communications expert and have no
- desire to design your own network protocols, you should probably use one of
- three AppleTalk protocols for sending and receiving data over the AppleTalk
- internet: the AppleTalk Transaction Protocol (ATP), the AppleTalk Session
- Protocol (ASP), or the AppleTalk Data Stream Protocol (ADSP).
-
- ATP is a lower-level protocol than ASP or ADSP. You cannot use ATP to establish
- a session and keep it open; rather, you request data from another socket or send
- a response (up to eight packets of data) from your socket to another socket that
- has requested data. You should use ATP if you want only to send a small amount
- of data and do not need the overhead required to maintain an open connection.
- ATP is described in the AppleTalk Manager chapters of Volume II and Volume V.
-
- ASP is designed to support a session between a server and one or more
- workstations. It is an asymmetrical protocol: all exchanges are initiated by a
- workstation and responded to by a server. The server cannot initiate an exchange
- of data except to send an attention message to a workstation, asking the
- workstation to request data from the server. An application running on a
- workstation must make calls to ASP to communicate with any server that uses ASP.
- If you want to develop a new type of asymmetrical, transaction-oriented server,
- you should consider using ASP to implement it. ASP is described in the AppleTalk
- Manager chapter of Volume V.
-
- ADSP is a symmetrical protocol that you can use to establish and maintain a
- connection between two equal entities. Either end of an ADSP connection can send
- data at any time. Although ADSP is a client of DDP, and therefore sends and
- receives data in packets (as do ATP and ASP), to an application using ADSP the
- data appears to be sent and received as a continuous stream. In addition to the
- duplex data stream maintained by an ADSP session, ADSP allows either end of a
- connection to send an attention message to the other end. You can use ADSP to
- establish two-way communication between computers, such as an interoffice party
- line or a terminal-emulation program. If you want to develop a server that
- requires two-way communication, you should consider using ADSP to implement it.
- ADSP is described in “Using ADSP” later in this chapter.
-
- _______________________________________________________________________________
-
- æKY The….MPP…Driver
- æC »THE .MPP DRIVER AppleTalk Manager
- _______________________________________________________________________________
-
- Within the AppleTalk Manager, the .MPP driver implements the Routing Table
- Maintenance Protocol (RTMP) stub, the Name Binding Protocol (NBP), the AppleTalk
- Echo Protocol (AEP), the Datagram Delivery Protocol (DDP), and the LocalTalk
- Link Access Protocol (LLAP). The AppleTalk Phase 2 version of the .MPP driver
- includes a new function that returns information about the .MPP driver,
- functions that send messages to routines in the AppleTalk Transition Queue, and
- a new wildcard character for NBP.
-
- _______________________________________________________________________________
-
- æKY Getting…Information…About…the….MPP…Driver
- æC »Getting Information About the .MPP Driver AppleTalk Manager
- _______________________________________________________________________________
-
- You can use the PGetAppleTalkInfo function to obtain information about the .MPP
- driver. In addition to the node ID and other information pointed to by the
- ABusVars global variable (discussed in the AppleTalk Manager chapter of Volume
- II), the PGetAppleTalkInfo function returns
-
- • a pointer to the .MPP driver’s device control entry data structure (DCE)
-
- • configuration flags, which indicate the status of certain conditions that
- are set at startup
-
- • a value (the selfSend flag) that indicates whether the node can send
- packets to itself
-
- • the network number range for the network to which the node is attached
-
- • the 8-bit node ID and 16-bit network number of the node
-
- • the 8-bit node ID and 16-bit network number of the last router from which
- the node has heard
-
- • the maximum capacities of the .MPP driver—such as the maximum number of
- protocol handlers and the maximum number of static sockets allowed by
- this driver
-
- • a pointer to the registered names queue
-
- • the node address of the node on the underlying data link (for example,
- the Ethernet hardware address)
-
- • the node’s zone name
-
- The data link address (for example, the Ethernet hardware address) and the zone
- name are returned only for extended networks; that is, network types that allow
- more than one network per cable. You must allocate memory for and provide
- pointers to the data buffers into which the PGetAppleTalkInfo function returns
- the data link address and zone name. You use the laLength parameter to specify
- the length of the data link address you want returned; the function returns the
- actual length of the data in the laLength parameter and returns the data in the
- buffer you provide.
-
- Note: Always use the PGetAppleTalkInfo function to obtain information about the
- .MPP driver. You can no longer rely on the validity of the global variables
- described in the AppleTalk chapter of Inside Macintosh, Volume II.
-
- FUNCTION PGetAppleTalkInfo (thePBptr: MPPPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always PGetAppleTalkInfo
- Æ 28 version word version of function
- ¨ 30 varsPtr pointer pointer to MPP globals
- ¨ 34 dcePtr pointer pointer to DCE for .MPP
- ¨ 38 portID word port number
- ¨ 40 configuration long configuration flags
- ¨ 44 selfSend word nonzero if self-send is enabled
- ¨ 46 netLo word low value of the network range
- ¨ 48 netHi word high value of the network range
- ¨ 50 ourAddr long local 24-bit AppleTalk address
- ¨ 54 routerAddr long 24-bit address of router
- ¨ 58 numOfPHs word max number of protocol handlers
- ¨ 60 numOfSkts word max number of static sockets
- ¨ 62 numNBPEs word max concurrent NBP requests
- ¨ 64 ntQueue pointer pointer to registered name queue
- ´ 68 laLength word length in bytes of data link address
- (extended networks only)
- Æ 70 linkAddr pointer pointer to data link address buffer
- (extended networks only)
- Æ 74 zoneName pointer pointer to zone name buffer
-
- The PGetAppleTalkInfo function returns information about the .MPP driver. If the
- node on which your program is running happens also to be running AppleTalk
- Internet Router software in the background, there may be more than one set of
- .MPP global variables in RAM. To make sure you are obtaining information about
- the .MPP driver that handles application software, always use the
- PGetAppleTalkInfo function rather than the Device Manager’s PBControl function.
- If you are using assembly language, or want to use the PBControl function, you
- must use a device driver reference number of –10 for the .MPP driver.
-
- Parameters
-
- ioResult
- The result of the function. When you execute the function asynchronously, the
- function sets this parameter to 1 and returns a function result of noErr as soon
- as the function begins execution. When the function completes execution, it sets
- the ioResult parameter to the actual result code.
-
- csCode
- Routine selector, automatically set by the MPW interface. Always equal to
- PGetAppleTalkInfo for this function.
-
- version
- The version number of the PGetAppleTalkInfo function you are calling. For
- version number 53 of the .MPP driver, this number is always 1.
-
- varsPtr
- A pointer to the MPP global variables. The MPP global variables are discussed in
- “Protocol Handlers and Socket Listeners” in Chapter 10 of Volume II.
-
- dcePtr
- A pointer to the device control entry (DCE) data structure for the .MPP driver.
- The DCE is described in the Device Manager chapters of Volumes II and V.
-
- portID
- The port number for the .MPP driver. The port number is always 0 unless you are
- requesting information for an .MPP driver being used by a router.
-
- configuration
- A 32-bit long word of configuration flags. The following flags are currently
- defined:
-
- Bit Flag Description
- 31 SrvAdrBit TRUE (1) if the routine that opened the .MPP driver requested a
- server node number. Server node numbers are described in the AppleTalk Manager
- of Volume V. This flag indicates only that the server-node number was requested,
- not that it was returned. Some AppleTalk devices, such as EtherTalk, do not
- honor a request for a server-node number.
-
- 30 RouterBit TRUE (1) if an AppleTalk Internet Router was loaded at system
- startup (that is, there's a router operating on the same node as your
- application). A router can be loaded but not active.
-
- 15 ExtendedBit TRUE (1) if the node is on an extended network.
-
- 7 BadZoneHintBit TRUE (1) if the zone name of the node you are on was not
- the same as the zone name stored in parameter RAM (sometimes referred to as the
- zone name hint) when the .MPP driver was opened. If the zone name hint is
- invalid, then the AppleTalk Manager uses the default zone for the network.
-
- 6 OneZoneBit TRUE (1) if only one zone is assigned to your extended network
- or if you are not on an extended network.
-
- selfSend
- This parameter is nonzero if the ability of a node to send packets to itself is
- enabled. Use the PSetSelfSend function, described in the AppleTalk Manager
- chapter of Volume V, to enable or disable this feature.
-
- netLo
- The low value of the range of network numbers on the local cable. Only extended
- networks can have a range of network numbers. For a nonextended network, this
- parameter returns the network number.
-
- netHi
- The high value of the range of network numbers on the local cable. Only extended
- networks can have a range of network numbers. For a nonextended network, this
- parameter returns the network number.
-
- ourAddr
- The 24-bit AppleTalk network address of the node you are on. The least
- significant byte of the longword is the node ID. The middle 16 bits are the
- network number. The most significant byte of the longword is reserved for use by
- Apple Computer, Inc.
-
- routerAddr
- The 24-bit AppleTalk network address of the last router from which your node
- heard traffic. The least significant byte of the longword is the node ID. The
- middle 16 bits are the network number. The most significant byte of the longword
- is reserved for use by Apple Computer, Inc. You should always use this address
- when you want to communicate with a router.
-
- numOfPHs
- The maximum number of protocol handlers that this .MPP driver allows.
-
- numOfSkts
- The maximum number of statically assigned sockets that this .MPP driver allows.
- Statically assigned sockets are described in Inside AppleTalk.
-
- numNBPEs
- The maximum number of concurrent requests to NBP that this .MPP driver allows.
-
- ntQueue
- A pointer to the first entry in the names table for the local node. You can use
- NBP routines to look up and register names in the names table. The names table
- is described in “Name-Binding Protocol” in Chapter 10 of Volume II.
-
- laLength
- When you call the PGetAppleTalkInfo function on a node on an extended network,
- you use this parameter to specify the number of bytes of the data link address
- the function should place in the buffer pointed to by the LinkAddr parameter. If
- you request more bytes than the total number of bytes in the address, then the
- function returns in the laLength parameter the actual number of bytes it placed
- in the buffer. If the address is longer than the size of the buffer, then the
- PGetAppleTalkInfo function fills the buffer and returns in the laLength
- parameter the actual length of the address, not the number of bytes returned.
- The function does not return an error when the buffer is too large or too small
- for the address.
-
- linkAddr
- A pointer to a buffer for the data link address returned for extended networks
- only. You use the laLength parameter to specify the number of bytes of the
- address that you want placed in this buffer. You must allocate a buffer large
- enough to hold the number of bytes you specify. Speficy NIL for this parameter
- if you do not want the function to provide a data-link address.
-
- zoneName
- A pointer to a buffer into which the PGetAppleTalkInfo function places the local
- node’s zone name. You must allocate a buffer of at least 33 bytes to hold this
- data, or specify NIL for the ZoneName parameter if you do not want to obtain the
- zone name. This field is returned only if the node is on an extended network.
-
- Result codes
- noErr 0 no error
- _______________________________________________________________________________
-
- æKY A…New…NBP…Wildcard…Character
- æC »A New NBP Wildcard Character AppleTalk Manager
- _______________________________________________________________________________
-
- The Name-Binding Protocol (NBP) allows the use of certain wildcard characters in
- AppleTalk names. You can use a wildcard character in a call to the PLookupName
- function, for example, to obtain names and addresses of all the entities in a
- given zone. NBP now supports the following wildcard characters:
-
- NBP Wildcard characters
-
- = All possible values. This character can be used alone instead of a name in
- the object or type fields.
-
- * This zone. This character can be used alone instead of the zone name for the
- local zone only.
-
- ≈ Any or no characters in this position. This character can be used to obtain
- matches for object or type fields. For example, pa≈l matches pal, paul,
- paper ball, and so forth. You can use only one double tilde (≈) character in
- any string. Press option-x to type the double tilde character on a Macintosh
- keyboard. If you use the double tilde character alone, it has the same
- meaning as the equal sign (=). Note that any node not running AppleTalk
- Phase 2 drivers will not recognize this character.
-
- _______________________________________________________________________________
-
- æKY The…LAP…Manager
- æC »THE LAP MANAGER AppleTalk Manager
- _______________________________________________________________________________
-
- The LAP Manager is a set of operating system utilities that provide a standard
- interface between the AppleTalk protocols and the various link access protocols,
- such as EtherTalk (ELAP), TokenTalk (TLAP), and LocalTalk (LLAP). Because the
- LAP Manager is running even when the .MPP driver is not open, the LAP Manager
- maintains the AppleTalk Transition Queue. The LAP Manager also contains protocol
- handlers for certain types of 802.2 packets. This section describes the
- AppleTalk Transition Queue and the LAP Manager 802.2 protocol handler, tells you
- how to add or remove an AppleTalk Transition Queue entry, and describes how to
- attach or detach your own 802.2 protocol handler.
-
- _______________________________________________________________________________
-
- æKY The…AppleTalk…Transition…Queue
- æC »The AppleTalk Transition Queue AppleTalk Manager
- _______________________________________________________________________________
-
- At any given time there might be two or more applications running that use
- AppleTalk. If one of these applications opens or closes the AppleTalk drivers,
- the other AppleTalk applications are affected. To ensure that your application
- is not adversely affected by such an event, your application can place an entry
- in the AppleTalk Transition Queue. The AppleTalk drivers send a message to each
- application that is listed in the AppleTalk Transition Queue each time a routine
-
- • opens the .MPP driver
- • closes the .MPP driver
- • indicates that it intends to close the .MPP driver
- • denies permission to close the .MPP driver
- • cancels its intention to close the .MPP driver
-
- Each of these events is referred to as an AppleTalk transition.
-
- Because opening or closing the .MPP driver opens or closes the .ATP and .XPP
- drivers as well, and bacause the .MPP driver must be open before an application
- can open the .DSP driver, knowing the status of the .MPP driver is tantamount to
- knowing the status of all AppleTalk drivers.
-
- Because the .MPP driver is not necessarily open when the AppleTalk Transition
- Queue must be called, the LAP Manager maintains the queue. Each entry in the
- AppleTalk Transition Queue is defined by the ATQentry record type.
-
- TYPE ATQentry = RECORD
- qLink: ATQentryPtr; {next queue entry}
- qType: INTEGER; {unused}
- CallAddr: ProcPtr; {pointer to your routine}
- END;
-
- ATQentryptr = ^ATQentry;
-
- When you want to add an entry to the AppleTalk Transition Queue, you must create
- an ATQentry record and give the LAP Manager a pointer to this record. The qLink
- field is a pointer to the next queue entry. You should set this field to NIL;
- the LAP Manager fills it in when an application adds another entry to the queue.
- The qType field is not used, but is present to maintain consistency with other
- operating system queues . The CallAddr field is a pointer to a routine that you
- provide. Your routine must handle the AppleTalk transition routines described in
- “How the AppleTalk Manager Calls Your AppleTalk Transition Queue Routine” later
- in this chapter.
-
- Because you allocate the memory for the AppleTalk Transition Queue entry, you
- can add as many fields to the end of the entry as you wish for your own
- purposes. Whenever your routine is called, the caller provides you with a
- pointer to the queue entry so that you can have access to the information you
- stored at the end of your queue entry.
-
- _______________________________________________________________________________
-
- æKY Adding…and…Removing…AppleTalk…Transition…Queue…Entries
- æC »Adding and Removing AppleTalk Transition Queue Entries AppleTalk Manager
- _______________________________________________________________________________
-
- There are three LAP Manager procedures you can use that are related to the
- AppleTalk Transition Queue:
-
- • The LAPAddATQ procedure adds an entry to the AppleTalk Transition Queue.
- You provide in the A0 register a pointer to an ATQentry record. The
- CallAddr field of the ATQentry record holds a pointer to your routine.
- The LAP Manager fills in the qLink field with a pointer to the next queue
- entry.
-
- • The LAPRmvATQ procedure removes an entry from the AppleTalk Transition
- Queue. You provide in the A0 register a pointer to your queue entry.
-
- • The LAPGetATQ procedure returns in the A1 register a pointer to the
- AppleTalk Transition Queue header.
-
- Assembly-language note: From assembly language, you call LAP Manager routines
- by placing a routine selector in the D0 register and executing a JSR instruction
- to an offset 2 bytes past the start of the LAP manager. Before you call the
- LAPAddATQ or LAPRmvATQ routines, you must also place a pointer to your AppleTalk
- Transition Queue entry in the A0 register. The LAPGetATQ routine returns a
- pointer to the AppleTalk Transition Queue header in the A1 register.
- Here is an assembly-language call to a LAP Manager routine:
-
- LAPMgrPtr EQU $B18 ;Entry point for LAP Manager
- LAPMgrCall EQU 2 ;Offset to LAP Manager routines
- ATQEntry EQU * ;AppleTalk Transition Queue entry
- ...
-
- MOVEQ #Code,D0 ;Place routine selector in D0
- MOVE.L LAPMgrPtr,An ;Put LAP Mgr entry pt in An
- MOVE.L ATQEntry,A0 ;Put ATQ entry in A0 (LAPAddATQ & LAPRmvATQ only)
- JSR LAPMgrCall(An) ;Jump to start of LAP Mgr routines
-
- You can use LAP Manager routines to add an entry to the AppleTalk Transition
- Queue, remove an entry from the queue, or obtain a pointer to the AppleTalk
- Transition Queue header. See “Using the AppleTalk Transition Queue,” earlier in
- this chapter, for a description of the queue and how to use it.
-
- PROCEDURE LAPAddATQ (entryPtr: pointer);
-
- On entry D0: 23
- A0: pointer to ATQentry record
-
- The LAPAddATQ procedure adds an entry to the AppleTalk Transition Queue. The
- entryPtr parameter is a pointer to an ATQentry record. The ATQentry record
- includes a pointer to the routine that AppleTalk calls when any routine opens or
- closes the .MPP driver, or indicates that it intends to close the .MPP driver.
- The ATQentry is described in “Using the AppleTalk Transition Queue” earlier in
- this chapter.
-
- PROCEDURE LAPRmvATQ (entryPtr: pointer);
- \
- On entry D0: 24
- A0: pointer to ATQentry record
-
- The LAPRmvATQ procedure removes an entry from the AppleTalk Transition Queue.
- The entryPtr parameter is a pointer to an ATQentry record.
-
- PROCEDURE LAPGetATQ (VAR eqPtr: pointer);
-
- On entry D0: 25
- On exit A1: pointer to AppleTalk Transition Queue header
-
- The LAPGetATQ procedure returns a pointer to the AppleTalk Transition Queue
- header.
- _______________________________________________________________________________
-
- æKY Sending…Messages…to…the…AppleTalk…Transition…Queue
- æC »Sending Messages to the AppleTalk Transition Queue AppleTalk Manager
- _______________________________________________________________________________
-
- Whereas it is unlikely that opening the .MPP driver will adversely affect
- another program, an application should never close the .MPP driver, because
- another program might be using it. Under certain circumstances, however, the
- system might close the .MPP driver, provided no application objects. The system
- uses the .MPP driver’s PATalkClosePrep function to inform each routine in the
- AppleTalk Transition Queue that it intends to close the .MPP driver, giving each
- routine in the queue the opportunity to deny permission to do so.
-
- The system provides a pointer to a 255-byte buffer when it calls the
- PATalkClosePrep function. If any routine in the AppleTalk Transition Queue
- denies permission to close the .MPP driver, it places a name in the buffer and
- returns control to the AppleTalk Manager. The name that the routine places in
- the buffer should be the name of the application that placed the entry in the
- queue. The PATalkClosePrep function then calls each routine in the AppleTalk
- Transition Queue a second time to inform it that the request to close the .MPP
- driver has been canceled. If any routine in the AppleTalk Transition Queue
- denies permission to close the .MPP driver, the PATalkClosePrep function returns
- the result code closeErr.
-
- If any routine denies permission to close the .MPP driver, the system displays a
- dialog box informing the user that another application is using the .MPP driver,
- and showing the name that the AppleTalk Transition Queue routine placed in the
- buffer. The dialog box gives the user the option of canceling the request to
- close AppleTalk, or of closing AppleTalk anyway.
-
- Note: If the user chooses to close AppleTalk despite the fact that an
- application is using it, the system calls the MPPClose function. AppleTalk calls
- each application in the AppleTalk Transition Queue again, this time informing it
- that AppleTalk is about to close. In this case, your AppleTalk Transition Queue
- routine must prepare for the imminent closing of AppleTalk; it cannot deny
- permission to the MPPClose function.
-
- FUNCTION PATalkClosePrep (thePBptr: MPPPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- Æ 26 csCode word always PATalkClosePrep
- Æ appName pointer buffer for name of application that denies request
-
- The PATalkClosePrep function calls each routine listed in the AppleTalk
- Transition Queue to request permission to close the .MPP driver.
- The routine that calls the PATalkClosePrep function must allocate a 255-byte
- buffer and provide a pointer to it in the appName parameter. If a routine in the
- AppleTalk Transition Queue denies permission to close the .MPP driver, that
- routine places a name in the buffer pointed to by the appName parameter, and the
- AppleTalk Manager calls each routine in the AppleTalk Transition Queue a second
- time to inform it that the request to close the .MPP driver has been canceled.
- The PATalkClosePrep function then returns the result code closeErr, indicating
- that the calling routine may not close the .MPP driver. The csCode parameter is
- a routine selector; it is always equal to PATalkClosePrep for this function.
-
- Result codes
- noErr 0 no error
- closeErr –24 permission to close .MPP driver was denied
-
- The system can use the PCancelATClosePrep function to undo the effects of the
- PATalkClosePrep function. The system uses this function, for example, if some
- condition prevents it from closing the .MPP driver even though each routine
- listed in the AppleTalk Transition Queue gave permission to close it. When the
- system calls the PCancelATClosePrep function, the AppleTalk Manager calls each
- routine in the AppleTalk Transition Queue to inform it that the request to close
- the .MPP driver has been canceled.
-
- FUNCTION PCancelATClosePrep (thePBptr: MPPPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- Æ 26 csCode word always PCancelATClosePrep
-
- The PCancelATClosePrep function undoes the effects of the PATalkClosePrep
- function. The PCancelATClosePrep function calls each routine in the AppleTalk
- Transition Queue to inform it that the request to close the .MPP driver has been
- canceled.
-
- The operating system uses this function, for example, if some condition prevents
- it from closing the .MPP driver even though each routine listed in the AppleTalk
- Transition Queue gave permission to close it.
-
- The csCode parameter is a routine selector, always equal to PCancelATClosePrep
- for this function.
-
- Result codes
- noErr 0 no error
- _______________________________________________________________________________
-
- æKY How…the…AppleTalk…Manager…Calls…Your…Transition…Queue…Routine
- æC »How the AppleTalk Manager Calls Your Transition Queue Routine AppleTalk Manager
- _______________________________________________________________________________
-
- When you have used the LAPAddATQ function to add an entry to the AppleTalk
- Transition Queue, the AppleTalk Manager calls your routine when any of the
- following AppleTalk transitions occurs:
-
- • A routine opens the .MPP driver.
- • A routine closes the .MPP driver.
- • A routine calls the ATalkClosePrep function.
- • One of the routines in the AppleTalk Transition Queue denies permission
- for the routine that called the ATalkClosePrep function to close
- AppleTalk, or a routine executes the PCancelATClosePrep function.
-
- When the AppleTalk Manager calls your AppleTalk Transition Queue routine, the
- first item on the stack (after the return address) is a routine selector. There
- is one routine selector for each type of transition:
-
- Routine selector Transition
- 0 .MPP driver opened
- 2 .MPP driver about to close
- 3 ATalkClosePrep function has been called
- 4 Closing of .MPP driver has been canceled
-
- The interface between the AppleTalk Transition Queue and your routine follows
- the conventions of the C language: Your routine must preserve all registers
- except D0, D1, D2, A0 and A1; all parameters are passed on the stack as long
- words.
-
- Note: Because the number of parameters that an AppleTalk Transition Queue
- routine must read off the stack varies with the routine selector, and because
- the routine must be able to place a value in the D0 register, you cannot use
- Pascal to write an AppleTalk Transition Queue routine.
-
- When an application calls the MPPOpen function to open the .MPP driver, the
- AppleTalk Manager calls every routine listed in the AppleTalk Transition Queue
- after it opens the .MPP driver. When the AppleTalk Manager calls your AppleTalk
- Transition Queue routine to tell it that the .MPP driver has been opened, the
- stack looks like this:
-
- SP Æ Return address (4 bytes)
- Routine selector; 0 when .MPP opens (4 bytes)
- Pointer to AppleTalk Transition Queue entry (4 bytes)
- Pointer to Device Manager’s parameter block (4 bytes)
- previous contents
-
- If the .MPP driver is already open and a routine executes the MPPOpen function,
- the AppleTalk Manager does not call the routines in the AppleTalk Transition
- Queue.
-
- You can use the pointer to your routine’s entry in the AppleTalk Transition
- Queue to get access to any fields at the end of the queue entry that you
- allocated for your own use. The last item on the stack is a pointer to the start
- of the Device Manager extended parameter block used by the routine that opened
- the .MPP driver. This pointer is provided for your information only; you must
- not change any of the fields in this parameter block.
-
- Your AppleTalk Transition Queue routine can perform any tasks you wish in
- response to the notification that the .MPP driver has been opened, such as using
- NBP to register a name on the internet.
-
- When any routine calls the MPPClose function to close the .MPP driver, the
- AppleTalk Manager calls every routine listed in the AppleTalk Transition Queue
- before the .MPP driver closes. When the AppleTalk Manager calls your routine to
- tell it that the .MPP driver is about to close, the stack looks like this:
-
-
- SP Æ Return address (4 bytes)
- Routine selector; 2 when .MPP is about to close (4 bytes)
- Pointer to AppleTalk Transition Queue entry (4 bytes)
- previous contents
-
- If the .MPP driver is already closed and a routine executes the MPPClose
- function, the AppleTalk Manager does not call the routines in the AppleTalk
- Transition Queue.
-
- You can use the pointer to your routine’s entry in the AppleTalk Transition
- Queue to get access to any fields at the end of the queue entry that you
- allocated for your own use.
-
- Your routine can perform any tasks you wish to prepare for the imminent closing
- of AppleTalk, such as ending a session with a remote terminal and informing the
- user that the connection is being closed. You must return control to the
- AppleTalk Manager as quickly as possible. When the AppleTalk Manager calls your
- routine with a routine selector of 2, you cannot prevent the .MPP driver from
- closing.
-
- When a routine calls the ATalkClosePrep function to inform the AppleTalk Manager
- that it wants to close the .MPP driver, the AppleTalk Manager calls every
- routine listed in the AppleTalk Transition Queue to request permission to close
- the .MPP driver. When the AppleTalk Manager calls your routine to request
- permission to close the .MPP driver, the stack looks like this:
-
-
- SP Æ Return address (4 bytes)
- Routine selector; 3 to ask permission to close .MPP (4 bytes)
- Pointer to AppleTalk Transition Queue entry (4 bytes)
- Pointer to pointer to name of client (4 bytes)
- previous contents
-
- Your routine can return either a longword of zeros in the D0 register,
- indicating that it accepts the request to close, or a nonzero value in the D0
- register, indicating that it denies the request to close.
- You can use the pointer to your routine’s entry in the AppleTalk Transition
- Queue to get access to any fields at the end of the queue entry that you
- allocated for your own use.
-
- The last parameter on the stack is a pointer to the clientName field (offset 28)
- in the .MPP driver parameter block that was used by the routine that called the
- PATalkClosePrep function. This field contains a pointer to a 255-byte buffer. If
- you intend to deny the request to close AppleTalk, you should place a string in
- this buffer containing the name of your application. The routine that called the
- PATalkClosePrep function can then display a dialog box telling the user the name
- of the application that is currently using AppleTalk.
-
- Because the AppleTalk Manager calls your routine again (with the routine
- selector set to 2) before the .MPP driver actually closes, it is not necessary
- for your routine to do anything other than grant or deny permission in response
- to being called with the routine selector set to 3. However, you might want to
- prohibit the users from opening new sessions or establishing new connections
- while you are waiting for the .MPP driver to close.
-
- When a routine calls the PCancelATClosePrep function to cancel the effects of
- the PATalkClosePrep function, or when any routine in the AppleTalk Transition
- Queue denies permission for the .MPP driver to close, the AppleTalk Manager
- calls every routine listed in the AppleTalk Transition Queue to inform it that
- the request to close the .MPP driver has been canceled. When the AppleTalk
- Manager calls your AppleTalk Transition Queue routine to cancel a request to
- close the .MPP driver, the stack looks like this:
-
-
- SP Æ Return address (4 bytes)
- Routine selector; 4 to cancel a close (4 bytes)
- Pointer to AppleTalk Transition Queue entry (4 bytes)
- previous contents
-
- You can use the pointer to your routine’s entry in the AppleTalk Transition
- Queue to get access to any fields at the end of the queue entry that you
- allocated for your own use.
-
- If your routine performed any tasks to prepare for the closing of AppleTalk, it
- should reverse their effects when it is called with the routine selector set to
- 4.
-
- Listing 29-1 illustrates the use of the AppleTalk Transition Queue. It defines a
- routine that AppleTalk is to call when an AppleTalk transition occurs. This
- routine first checks the stack to determine why it is being called, and then
- acts accordingly. If the routine selector indicates that the .MPP driver has
- just opened, the listing uses NBP to register a name on the internet. If the
- .MPP driver is about to close, the routine calls ADSP to close the session and
- displays a dialog box informing the user that the session is being closed. If
- some application is asking permission to close the .MPP driver, the routine
- checks to see if your application has an open ADSP session. If your application
- has a current open ADSP session, the routine places the name of your application
- in the buffer provided by the client that called the PATalkClosePrep function,
- and places a 0 in the D0 register. If your application has no open ADSP session,
- the routine places a 1 in the D0 register. If AppleTalk is canceling a request
- to close the .MPP driver, the routine terminates without further action.
- Listing 29-1 also defines an entry to the AppleTalk Transition Queue that points
- to the routine, and calls the LAPAddATQ procedure to add this entry to the
- queue.
-
- Listing 29-1. Using the AppleTalk Transition Queue (TO BE PROVIDED)
-
- _______________________________________________________________________________
-
- æKY The…LAP…Manager…802.2…Protocol
- æC »The LAP Manager 802.2 Protocol AppleTalk Manager
- _______________________________________________________________________________
-
- The Institute of Electrical and Electronics Engineers (IEEE) has defined a
- series of communication protocols for use on a variety of networks. At the
- hardware and signaling level, these protocols include the 802.3 Ethernet
- protocol, the 802.4 Token Bus protocol, and the 802.5 Token Ring protocol. At
- the link access level, these protocols are all handled by another IEEE protocol,
- the 802.2 protocol. The AppleTalk LAP Manager includes two routines that allow
- you to attach and detach protocol handlers for 802.2 Type 1 data packets: the
- L802Attach and L802Detach routines. You can write an application that reads
- 802.2 Type 1 data packets, and use the L802Attach routine to install your
- application as a client of the LAP Manager. The ANSI/IEEE standards for the 802
- protocols are published by the Institute of Electrical and Electronics
- Engineers.
-
- The first 14 bytes of a packet sent or received by the .ENET driver are the
- header. The first 12 bytes consist of the destination and source data link
- addresses (such as the Ethernet hardware addresses). If the value of the last
- two bytes in the header is greater than 1500, then the .ENET driver treats that
- field as an Ethernet protocol type discriminator. See “The .ENET Driver,” later
- in this chapter, for more information on Ethernet protocols. If the value of the
- last two bytes in the header is less than 1500, then the packet is an 802.3
- protocol packet and the .ENET driver passes it to the LAP Manager.
-
- The LAP Manager receives the entire 802.3 packet from the .ENET driver. The
- first three bytes of the 802.3 data constitues the header for the 802.2
- protocol. The first byte of the 802.2 header is known as the destination service
- access point (DSAP). If the DSAP type field is equal to $AA, then the first five
- bytes of the 802.2 data constitutes a protocol discriminator known as the
- subnetwork access protocol (SNAP) type. If the SNAP type field is $00000080F3,
- indicating the AppleTalk Address Resolution Protocol (AARP), then the next four
- bytes of the 802.2 data constitutes a third type field, the AARP packet type.
- AARP is discussed in Inside AppleTalk.
-
- The following data packet header, for example, indicates an Ethernet packet
- containing AppleTalk data. The .ENET driver would deliver this packet to the
- AppleTalk Phase 1 device drivers.
-
- 02608C010203 02608C040506 809B
-
- By contrast, the following data packet header indicates an 802.3 packet
- containing AppleTalk data. The .ENET driver would deliver this packet to the
- AppleTalk Phase 2 LAP Manager
-
- 02608C010203 02608C040506 0060 AA AA 03 080007809B
-
- Similarly, the following data packet header indicates an 802.3 packet to be
- delivered to the EtherTalk AARP handler:
-
- 02608C010203 02608C040506 0060 AA AA 03 00000080F3 0001809B
-
- When you call the L802Attach function, you provide a pointer to your protocol
- handler, the reference number of the .ENET driver, and a pointer to a string
- containing one or more type fields. The type fields indicate the DSAP value and
- any other protocol type fields (such as the SNAP type and the AARP type). The
- LAP Manager delivers to your protocol handler any 802.2 data packets that have
- the protocol type you specify.
- _______________________________________________________________________________
-
- æKY Attaching…and…Detaching…802.2…Protocol…Handlers
- æC »Attaching and Detaching 802.2 Protocol Handlers AppleTalk Manager
- _______________________________________________________________________________
-
- You can attach to the LAP Manager your own protocol handler for 802.2 protocols.
- The LAP Manager has permanent handlers for certain types of EtherTalk packets.
- You cannot replace or override the permanent LAP Manager protocol handlers.
-
- FUNCTION L802Attach (Eref: word; handlerPtr: procptr; ProtType: pointer) :
- OSErr;
-
-
- On entry D0: 21
- D2: reference number of .ENET driver
- A0: pointer to your protocol handler
- A1: pointer to protocol specification
-
- On exit D0: nonzero if error
-
- The L802Attach function attaches to the LAP Manager a protocol handler for a
- specific IEEE 802.2 protocol type.
-
- The Eref parameter is the reference number of the .ENET driver that was returned
- by the OpenSlot function when you or somone else opened the .ENET driver. If you
- are not using the .ENET driver or a driver that uses the same interface as the
- .ENET driver, you cannot use the L802Attach function. The handlerPtr parameter
- is a pointer to your protocol handler.
-
- The ProtType parameter is a pointer to the protocol type specification for this
- protocol handler. The protocol type specification consists of one or more
- protocol type fields, each preceded by a length byte. The LAP Manager reads the
- protocol type fields in the 802.2 data packet header to determine to which
- protocol handler (if any) to deliver the packet. The first type field in your
- protocol specification is 1 byte long and is known as the destination service
- access point (DSAP). If the DSAP type field is equal to $AA, then the protocol
- type specification can contain a second type field, the 5-byte subnetwork access
- protocol (SNAP) type. If the SNAP type field is $00000080F3, indicating the
- AppleTalk Address Resolution Protocol (AARP), then the protocol type
- specification can contain a third type field, the 4-byte AARP protocol type.
- Terminate the list of protocol type fields with a byte of zeros.
-
- The following protocol type specification, for example, indicates an 802.3
- packet containing AppleTalk data. The .ENET driver would deliver this packet to
- the AppleTalk Phase 2 LAP Manager. The first byte, $01, is the length byte for
- the first protocol type field (the DSAP type field), $AA. The third byte, $05,
- is the length byte for the next protocol type field, the SNAP. The final byte
- ($00) terminates the type specification.
-
- 01 AA 05 08 00 07 80 9B 00
-
- The following protocol type specification indicates an 802.3 packet to be
- delivered to the EtherTalk AARP handler: Notice that the SNAP field is followed
- by an additional type field, the AARP protocol type.
-
- 01 AA 05 00 00 00 80 F3 04 00 01 80 9B 00
-
- See the ANSI/IEEE standard 802.2 for more information about 802.2 protocols, and
- Inside AppleTalk for more information about AARP.
-
- Result codes
- noErr 0 no error
-
- FUNCTION L802Detach (Eref: word; ProtType: pointer) : OSErr;
-
- On entry D0: 22
- D2: reference number of .ENET driver
- A1: pointer to protocol specification
-
- On exit D0: nonzero if error
-
- The L802Detach function detaches from the LAP Manager a protocol handler for a
- specific IEEE 802.2 protocol type.
-
- The Eref parameter is the reference number of the .ENET driver that was returned
- by the OpenSlot function when you or somone else opened the .ENET driver. The
- handlerPtr parameter is a pointer to your protocol handler.
-
- The ProtType parameter is a pointer to the protocol type specification for this
- protocol handler. You must specify exactly the same protocol type as you
- specified for the L802Attach function when you attached the protocol handler.
-
- Result codes
- noErr 0 no error
- _______________________________________________________________________________
-
- æKY AppleTalk…Data…Stream…Protocol…(ADSP)
- æC »APPLETALK DATA STREAM PROTOCOL (ADSP) AppleTalk Manager
- _______________________________________________________________________________
-
- One of the significant new features of AppleTalk introduced with AppleTalk Phase
- 2 is the AppleTalk Data Stream Protocol (ADSP), which provides a full-duplex
- data stream connection between two nodes in the AppleTalk internet. Like the
- AppleTalk Session Protocol, Printer Access Protocol, and AppleTalk Transaction
- Protocol, ADSP uses the Datagram Delivery Protocol to send its data over the
- internet. Therefore, even though ADSP appears to its clients to handle data as a
- stream of bytes, the data is actually transmitted and received by DDP in
- packets. ADSP takes advantage of this fact by including control and status
- information in the DDP packet header. You can use the .DSP driver functions
- described in “.DSP Driver Functions,” later in this chapter, to control an ADSP
- connection. The
- .DSP driver takes care of implementation of the ADSP protocol for you. To use
- ADSP, you must have the file named 'ADSP' in your system folder.
-
- Every ADSP connection is between two sockets in the AppleTalk internet. Each
- socket can establish simultaneous ADSP connections with several other sockets,
- but there can be only one ADSP connection between any two sockets at one time.
- When a pair of sockets establishes an ADSP connection, each socket client
- initializes and maintains a certain amount of control and state information that
- it uses for error checking and to synchronize communication with the other
- socket client.
-
- The combination of a socket and the ADSP information maintained by the socket
- client is referred to as a connection end. When two connection ends establish
- communication, the connection is considered an open connection. When both
- connection ends terminate the link and dispose of the connection information
- each maintains, the connection is considered a closed connection. If one
- connection end is established but the other connection end is unreachable or has
- disposed of its connection information, the connection is considered a half-open
- connection. No communication can occur over a half-open or closed connection. To
- prevent a half-open connection from tying up resources, ADSP automatically
- closes any half-open connection that cannot reestablish communications within
- two minutes.
-
- _______________________________________________________________________________
-
- æKY Using…ADSP
- æC »Using ADSP AppleTalk Manager
- _______________________________________________________________________________
-
- You can use the AppleTalk Data Stream Protocol to implement a data stream
- connection between any two sockets on the internet. (Note that although there
- can be only one ADSP connection between any two sockets, a single socket can
- maintain connections with several other sockets.) This section describes how to
- open, maintain, and close a connection between two sockets on an internet. It
- also describes how to establish and use a connection listener; that is, a
- connection end that waits passively to receive a connection request and then
- passes the connection request on to its client, the connection server. Finally,
- this section describes how to write a routine that ADSP calls when your
- connection end receives an unsolicited connection event.
- _______________________________________________________________________________
-
- æKY The…ADSP…Connection…Control…Block
- æC »The ADSP Connection Control Block AppleTalk Manager
- _______________________________________________________________________________
-
- When you establish an ADSP connection end, you must allocate a nonrelocatiable
- block of memory for, and provide a pointer to, a data structure known as a
- connection control block (CCB). The CCB is used by ADSP to store state
- information about the connection end. You may read the fields in the CCB to
- obtain information about the connection end, but you are not allowed to write to
- any of the fields except one, the userFlags field. The connection control block
- requires 242 bytes, and is defined by the TRCCB record.
-
- TPCCB = ^TRCCB;
-
- TRCCB = PACKED RECORD
- ccbLink: TPCCB; {link to next CCB}
- refNum: INTEGER; {user reference number}
- state: INTEGER; {state of the connection end}
- userFlags: Byte; {user flags for connection}
- localSocket: Byte; {local socket number}
- remoteAddress: AddrBlock; {remote end internet address}
- attnCode: INTEGER; {attention code received}
- attnSize: INTEGER; {size of attention data}
- attnPtr: Ptr; {pointer to attention data}
- reserved: PACKED ARRAY [1..220] OF Byte {reserved for use by ADSP}
- END;
-
- The internet address of the remote connection end is defined in the TRCCB record
- by an AddrBlock record:
-
- AddrBlock = PACKED RECORD
- aNet: INTEGER; {network number}
- aNode: Byte; {node ID}
- aSocket: Byte; {socket number}
- END;
-
- Field descriptions
-
- ccbLink
- Pointer to the next CCB. For use by ADSP only.
-
- refnum
- The reference number of the connection end. This number is assigned by ADSP when
- you establish the connection end.
-
- state
- The state of the connection end, as follows:
-
- State Value Meaning
- sListening 1 Socket is a connection listening socket; that is, a socket
- that accepts ADSP requests to open connections and passes them on to a socket
- client. Ordinarily used only by servers.
-
- sPassive 2 Socket client is inactive but capable of accepting an ADSP
- request to open a connection. Unlike a connection listening socket, which passes
- the open-connection request on to a routine that can establish the connection on
- any socket, a socket client in the sPassive state can accept an open-connection
- request only to establish itself as a connection end.
-
- sOpening 3 Socket client has sent an open-connection request and is waiting
- for acknowledgment.
-
- sOpen 4 Connection is open.
-
- sClosing 5 Socket client has requested that ADSP close the connection, and
- ADSP is sending data or waiting for acknowledgement of data it has sent before
- closing the connection.
-
- sClosed 6 Either connection end or ADSP has closed the connection.
-
- userFlags
- Flags that indicate an unsolicited connection event has occurred. An unsolicited
- connection event is an event initiated by ADSP or the remote connection end that
- is not in response to any .DSP function that you executed.
-
- Each time an unsolicited connection event occurs, ADSP sets a flag in the
- userFlags field of the CCB and calls the routine you specified in the
- userRoutine parameter to the dspInit command (if any). The user routine must
- read the userFlags field and then clear the flag to 0. ADSP cannot notify your
- routine of future events unless you clear the flag after each event.
-
-
- ADSP recognizes four types of unsolicited connection events, one corresponding
- to each of the flags in this field. The events and flags are defined as follows,
- where bit 7 is the most significant bit:
-
- Event Flag Bit Meaning
- eClosed 7 ADSP has been informed by the remote connection end that the
- remote connection end has closed the connection.
-
- eTearDown 6 ADSP has determined that the remote connection end is not
- responding, and so has closed the connection.
-
- eAttention 5 ADSP has received an attention message from the remote
- connection end.
-
- eFwdReset 4 ADSP has received a forward reset command from the remote
- client end, has discarded all ADSP data not yet delivered— including the data in
- the local client end’s receive queue—and has resynchronized the connection.
-
- none 3–0 Reserved
-
- localSocket
- The socket number through which DDP transmits and receives the ADSP packets.
-
- remoteAddress
- The internet address of the socket used by the remote connection end.
-
- attnCode
- The attention code received by ADSP when the remote connection end sends an
- attention message.
-
- attnSize
- The size of the attention message received by ADSP when the remote connection
- end sends an attention message.
-
- attnPtr
- A pointer to a buffer containing the attention message received by ADSP from the
- remote connection end.
-
- reserved
- A data buffer reserved for use by ADSP.
-
- _______________________________________________________________________________
-
- æKY The….DSP…Parameter…Block
- æC »The .DSP Parameter Block AppleTalk Manager
- _______________________________________________________________________________
-
- The .DSP commands use the AppleTalk preferred interface. Each .DSP command
- includes a pointer to a parameter block that includes all of the parameters
- needed by that command.
-
- The .DSP parameter block is defined by the DSPParamBlock record.
-
- DSPParamBlock = PACKED RECORD
- qLink: QElemPtr; {next queue entry}
- qType: INTEGER; {queue type}
- ioTrap: INTEGER; {routine trap}
- ioCmdAddr: Ptr; {routine address}
- ioCompletion: ProcPtr; {completion routine}
- ioResult: OsErr; {result code}
- ioNamePtr: StringPtr; {used only for Open routine}
- ioVRefNum: INTEGER; {volume reference number}
- ioCRefNum: INTEGER; {driver reference number}
- csCode: INTEGER; {primary command code}
- qStatus: LONGINT; {reserved for ADSP}
- ccbRefNum: INTEGER; {CCB reference number}
-
- CASE INTEGER OF
- dspInit,
- dspCLInit:
- (
- ccbPtr: TPCCB; {pointer to CCB}
- userRoutine: ProcPtr; {pointer to user routine}
- sendQSize: INTEGER; {size of send queue}
- sendQueue: Ptr; {pointer to send queue}
- recvQSize: INTEGER; {size of receive queue}
- recvQueue: Ptr; {pointer to receive queue}
- attnPtr: Ptr; {pointer to attention-message buffer}
- localSocket: Byte; {local socket number}
- );
-
- dspOpen,
- dspCLListen,
- dspCLDeny:
- (
- localCID: INTEGER; {local connection ID}
- remoteCID: INTEGER; {remote connection ID}
- remoteAddress: AddrBlock; {remote internet address}
- filterAddress: AddrBlock; {address filter}
- sendSeq: LONGINT; {send sequence number}
- sendWindow: INTEGER; {size of remote buffer}
- recvSeq: LONGINT; {receive sequence number}
- attnSendSeq: LONGINT; {attention send seq number}
- attnRecvSeq: LONGINT; {attention receive seq num}
- ocMode: Byte; {connection opening mode}
- ocInterval: Byte; {interval bet open requests}
- ocMaximum:Byte;{retries of open conn req}
- );
-
- dspClose,
- dspRemove:
- (
- abort: Byte; {abort send requests}
- );
-
- dspStatus:
- (
- statusCCB: TPCCB; {pointer to CCB}
- sendQPending: INTEGER; {bytes waiting in send queue}
- sendQFree: INTEGER; {available send-queue buffer}
- recvQPending: INTEGER; {bytes in receive queue}
- recvQFree: INTEGER; {avail receive-queue buffer}
- )
-
- dspRead,
- dspWrite:
- (
- reqCount: INTEGER; {requested number of bytes}
- actCount: INTEGER; {actual number of bytes}
- dataPtr: Ptr; {pointer to data buffer}
- eom: Byte; {1 if end of message}
- flush: Byte; {1 to send data now}
- )
-
- dspAttention:
- (
- attnCode: INTEGER; {client attention code}
- attnSize: INTEGER; {size of attention data}
- attnData: Ptr; {pointer to attention data}
- attnInterval: Byte; {reserved}
- )
-
- dspOptions:
- (
- sendBlocking: INTEGER; {send-blocking threshold}
- sendTimer: Byte; {reserved}
- rtmtTimer: Byte; {reserved}
- badSeqMax: Byte; {retransmit advice threshold}
- useCheckSum: Byte; {DDP checksum for packets}
- )
-
- dspNewCID:
- (
- newCID: INTEGER; {new connection ID}
- )
- END;
-
- The qLink, qType, ioTrap, ioCmdAddr, ioNamePtr, and ioVRefNum fields are filled
- in by the Device Manager; your application should not have to set or read these
- parameters. The ioResult parameter returns the result of the function; in the
- case that you call the function asynchronously, the Device Manager sets this
- field to 1 as soon as you call the function, and changes the field to the actual
- result code when the function completes execution. The ioCompletion parameter is
- a pointer to a completion routine that you can provide; the Device Manager calls
- your completion routine when it completes execution of the PBControl function.
- If you are not providing a completion routine, specify NIL for this field. The
- ioCRefNum and csCode fields specify the driver and the command to be executed;
- you must fill in the csCode field.
-
- The qStatus field is reserved for use by ADSP. The ccbRefNum field is a
- reference number for the connection control block. The CCB reference number is
- returned by ADSP in response to the dspInit command. You must specify this
- number as a parameter to every .DSP driver routine you call subsequently.
-
- The remaining parameters are used only for specific commands; each of these
- parameters is described in “.DSP Driver Commands” later in this chapter.
-
- _______________________________________________________________________________
-
- æKY Opening…and…Maintaining…an…ADSP…Connection
- æC »Opening and Maintaining an ADSP Connection AppleTalk Manager
- _______________________________________________________________________________
-
- To use ADSP to establish and maintain a connection between a socket on your
- local node and a remote socket, use the following procedure:
-
- 1. Use the MPPOpen command to open the .MPP driver and then use the OpenDriver
- command to open the .DSP driver. The OpenDriver routine returns the reference
- number for the .DSP driver; you must supply this reference number each time you
- call the .DSP driver.
-
- 2. Allocate nonrelocatable memory for a connection control block, send and
- receive queues, and an attention message buffer. If you need to allocate the
- memory dynamically while the program is running, use the NewPtr routine.
- Otherwise, the way in which you allocate the memory depends on the compiler you
- are using (the program listing at the end of this section shows how it’s done in
- Pascal). The memory that you allocate becomes the property of ADSP when you call
- the dspInit command to establish a connection end. You cannot write any data to
- this memory except by calling ADSP, and you must ensure that the memory remains
- locked until you call the dspRemove command to eliminate the connection end.
-
- The connection control block is 242 bytes. The attention message buffer must be
- 570 bytes. When you send bytes to a remote connection end, ADSP stores the bytes
- in a buffer called the send queue. It keeps the bytes you sent in the send queue
- until the remote connection end acknowledges their receipt, so that they are
- available to be retransmitted if necessary. When the local connection end
- receives bytes, it stores them in a buffer called the receive queue until you
- read them. The sizes you need for the send and receive queues depend on the
- lengths of the messages being sent.
-
- ADSP does not transmit data from the remote connection end until there is room
- for it in your receive queue. If your send or receive queues are too small, they
- limit the speed with which you can transmit and receive data. A queue size of
- 600 bytes should work well for most applications. If you are using ADSP to send
- a continuous flow of data, a larger data buffer will improve performance. If
- your application is sending or receiving the user’s keystrokes, a smaller buffer
- should be adequate. The constant minDSPQueueSize indicates the minimum queue
- size that you can use.
-
- If you are using a version of the .DSP driver prior to version 1.5, you must
- allocate send and receive queues that are 12% larger than the actual buffer
- sizes you need, to provide some extra space for use by the .DSP driver. Version
- 1.5 and later versions of the .DSP driver use a much smaller, and variable,
- portion of buffer space for overhead.
-
- 3. Use the dspInit command to establish a connection end. You must provide
- pointers to the connection control block, send buffer, receive buffer, and
- attention message buffer. You may also provide a pointer to the user routine
- that ADSP calls when your connection end receives an unsolicited connection
- event. User routines are discussed in “Writing a User Routine For Connection
- Events” later in this chapter.
-
- If there is a specific socket that you want to use for the connection end, you
- can specify the socket number in the localSocket parameter. If you want ADSP to
- assign the socket for you, specify 0 for the localSocket parameter. ADSP returns
- the socket number when the dspInit command completes execution.
-
- 4. If you wish to do so, you can use the NBPRegister function to add the name
- and address of your connection end to the node’s names table. The NBPRegister
- function is described in the AppleTalk Manager chapter of Volume II.
-
- 5. You can use the dspOptions command to set several parameters that control
- the behavior of the connection end. Because every parameter has a default value,
- the use of the dspOptions command is optional. You can specify values for the
- following parameters:
-
- • The sendBlocking parameter, which sets the maximum number of bytes that
- may accumulate in the send buffer before ADSP sends a packet to the
- remote connection end. You can experiment with different values of the
- sendBlocking parameter to determine which provides the best performance;
- the default value of 16 bytes gives good performance under most
- circumstances.
-
- • The badSeqMax parameter, which sets the maximum number of out-of-sequence
- data packets that the local connection end can receive before requesting
- the remote connection end to retransmit the missing data. Under most
- circumstances, the default value of 3 provides good performance.
-
- • The useCheckSum parameter, which determines whether DDP should compute a
- checksum and include it in each packet that it sends to the remote
- connection end. Using checksums slows communications slightly. Normally
- ADSP and DDP perform enough error checking to ensure safe delivery of all
- data; set the useCheckSum parameter to 1 only if you feel that the
- network is highly unreliable.
-
- 6. Call the dspOpen command to open the connection. The dspOpen command has
- four possible modes of operation: ocAccept, ocEstablish, ocRequest, and
- ocPassive. Normally you use either the ocRequest or ocPassive mode. You must
- specify one of these four modes for the ocMode parameter when you call the
- dspOpen command.
-
- The ocAccept mode is used only by connection servers. The ocEstablish mode is
- used by routines that determine their connection-opening parameters and
- establish a connection independently of ADSP, but use ADSP to transmit and
- receive data.
-
- Use the ocRequest mode when you want to establish communications with a specific
- socket on the internet. When you execute the dspOpen command in the ocRequest
- mode, ADSP sends an open-connection request to the address you specify.
-
- If the socket to which you send the open-connection request is a connection
- listener, the connection server that operates that connection listener can
- choose any socket on the internet to be the connection end that responds to the
- open-connection request. To restrict the socket from which you will accept a
- response to your open-connection request, specify a value for the filterAddress
- parameter to the dspOpen command. When your connection end receives a response
- from a socket that meets the restrictions of the filterAddress parameter, it
- acknowledges the response and ADSP completes the connection.
-
- To use the ocRequest mode, you must know the complete internet address of the
- remote socket, and the ADSP client at that address must either be a connection
- listener or have executed the dspOpen command in the ocPassive mode. You can use
- the NBPLookup function to obtain a list of names of objects on the internet and
- to determine the internet address of a socket when you know its name. The
- NBPLookup function is described in the AppleTalk Manager chapter of Volume II.
- Enhancements to the wildcard-lookup feature of NBP are discussed in “A New NBP
- Wildcard Character” earlier in this chapter.
-
- Use the ocPassive mode when you expect to receive an open-connection request
- from a remote socket. You can specify a value for the filterAddress parameter to
- restrict the network number, node ID, or socket number from which you will
- accept an open-connection request. When your connection end receives an
- open-connection request that meets the restrictions of the filterAddress
- parameter, it acknowledges the request and ADSP completes the connection.
-
- You can poll the state field in the connection control block to determine when
- the connection end is waiting to receive an open-connection request, when the
- connection end is waiting to receive an acknowledgment of an open-connection
- request, and when the connection is open. The CCB is described in “The ADSP
- Connection Control Block” earlier in this chapter. Alternatively, you can check
- the result code for the dspOpen command when the function completes execution.
- If the function returns the noErr result code, then the connection is open.
-
- 7. Use the dspRead command to read data that your connection end has received
- from the remote connection end. Use the dspWrite command to send data to the
- remote connection end. Use the dspAttention command to send attention messages
- to the remote connection end.
-
- The dspWrite command places data in the send queue. ADSP is a full-duplex,
- symmetric communication protocol. You can send data at any time, and your
- connection end can receive data at any time, even at the same time as you are
- sending data. ADSP transmits the data in the send queue when one of the
- following conditions occurs:
-
- • You call the dspWrite command with the flush parameter set to a nonzero
- number.
-
- • The number of bytes in the send queue equals or exceeds the blocking
- factor that you set with the dspOptions command.
-
- • The send timer expires. The send timer sets the maximum amount of time
- that can pass before ADSP sends all unsent data in the send queue to the
- remote connection end. ADSP calculates the best value to use for this
- timer and sets it automatically.
-
- • A connection event requires that the local connection end send an
- acknowlegment packet to the remote connection end.
-
- If you send more data to the send queue than it can hold, the dspWrite command
- does not complete execution until it has written all the data to the send queue.
- If you execute the dspWrite command asynchronously, ADSP returns control to your
- program and writes the data to the send queue as quickly as it can. This
- technique provides the most efficient use of the send queue by your program and
- by ADSP. Because ADSP does not remove data from the send queue until that data
- has not only been sent but also acknowledged by the remote connection end, using
- the flush parameter to the dspWrite command does not guarantee that the send
- queue is empty. You can use the dspStatus command to determine how much free
- buffer space is available in the send queue.
-
- The dspRead command reads data from the receive queue into your application’s
- private data buffer. ADSP does not transmit data until there is space available
- in the other end’s receive queue to accept it. Because a full receive queue
- slows the communication rate, you should read data from the receive queue as
- often as necessary to keep sufficient buffer space available for new data. You
- can use either of two techniques to do this:
-
- • Allocate a small receive queue (about 600 bytes) and call the dspRead
- command asynchronously. Your completion routine for the dspRead command
- should then call the dspRead command again.
-
- • Allocate a large receive queue and call the dspRead command less
- frequently.
-
- If there is less data in the receive queue than the amount you specify with the
- reqCount parameter to the dspRead command, the command does not complete
- execution until there is enough data available to satisfy the request. There are
- three exceptions to this rule: If the end-of-message bit in the ADSP packet
- header is set, the dspRead command reads the data in the receive queue, returns
- the actual amount of data read in the actCount parameter, and returns the eom
- parameter set to 1. If you have closed the connection end before calling the
- dspRead command (that is, the connection is half open), the command reads
- whatever data is available and returns the actual amount of data read in the
- actCount parameter. If ADSP has closed the connection before you call the
- dspRead command , the function returns the noErr result code with the actCount
- parameter set to 0 and the eom parameter set to 0.
-
- In addition to the byte stream data format implemented by the dspRead and
- dspWrite commands, ADSP provides a mechanism for sending and receiving control
- signals or information separate from the byte stream. You use the dspAttention
- command to send an attention code and an attention message to the remote
- connection end. When your connection end receives an attention message, ADSP’s
- interrupt handler sets the eAttention flag in the userFlags field of the
- connection control block and calls your user routine. Your user routine must
- clear the userFlags field, and can then read the attention code and attention
- message and take whatever action you deem appropriate.
-
- Because ADSP is often used by terminal emulation programs and other applications
- that pass the data they receive on to the user without processing it, attention
- messages provide a mechanism for the applications that are clients of the
- connection ends to communicate with each other. For example, you could use
- attention messages to implement a handshaking and data checking protocol for a
- program that transfers disk files between two applications, neither one of which
- is a file server. Or a database server on a mainframe computer that uses ADSP to
- communicate with Macintosh computer workstations could use the attention
- mechanism to inform the workstations when the database is about to be closed
- down for maintenance.
-
- 8. When you are ready to close the ADSP connection, you can use the dspClose or
- dspRemove commands to close the connection end. Use the dspClose command if you
- intend to open another connection using that connection end, and do not want to
- release the memory you allocated for the connection end. Use the dspRemove
- command if you are completely finished with the connection end and want to
- release the memory.
-
- You can continue to read data from the receive queue after you have called the
- dspClose command, but not after you have called the dspRemove command. You can
- use the dspStatus command to determine whether there is any data remaining in
- the receive queue, or you can read data from the receive queue until both the
- actCount and eom fields of the dspRead parameter block return 0.
-
- If you set the abort parameter for the dspClose or dspRemove commands to 0, then
- ADSP does not close the connection or the connection end until it has sent—and
- received acknowledgment for—all data in the send queue and any pending attention
- messages. If you set the abort parameter to 1, then ADSP discards any data in
- the send queue and any attention messages that have not already been sent.
-
- After you have executed the dspRemove command, you can release the memory you
- allocated for the connection control block and data buffers.
-
- Listing 29-2 illustrates the use of ADSP. It opens the .MPP and .DSP drivers,
- and allocates memory for its internal data buffers, for the CCB, and for the
- send, receive, and attention message buffers. Then it uses the dspInit command
- to establish a connection end, and uses NBP to register the name of the
- connection end on the internet. The routine uses the dspOptions command to set
- the blocking factor to 24 bytes. Next, it uses NBP to determine the address of a
- socket whose name was chosen by the user and sends an open-connection request
- (dspOpen) to that socket. When the dspOpen command completes execution, the
- routine sends data and an attention message to the remote connection end, and
- reads data from its receive buffer. Finally, the routine closes the connection
- end with the dspRemove command and releases the memory it allocated.
-
- Listing 29-2. Using ADSP to establish and use a connection (TO BE PROVIDED)
-
- _______________________________________________________________________________
-
- æKY Creating…and…Using…a…Connection…Listener
- æC »Creating and Using a Connection Listener AppleTalk Manager
- _______________________________________________________________________________
-
- A connection listener is a special sort of ADSP connection end that cannot
- receive or transmit data streams or attention messages. The sole function of a
- connection listener is to wait passively to receive an open-connection request
- and to inform its client, the connection server, when it receives one. The
- connection server can then accept or deny the open-connection request. If it
- accepts the request, the connection server selects a socket to use as a
- connection end, establishes a connection end on that socket, and sends an
- acknowledgement and connection request back to the requesting connection end.
- The connection server can use the same socket as it used for the connection
- listener, or can select a different socket as the connection end.
-
- Use the following procedure to establish a connection listener and to use that
- connection listener to open a connection with a remote connection end:
-
- 1. Use the MPPOpen command to open the .MPP driver and then use the OpenDriver
- command to open the .DSP driver. The OpenDriver routine returns the reference
- number for the .DSP driver; you must supply this reference number each time you
- call the .DSP driver.
-
- 2. Allocate nonrelocatable memory for a connection control block. A connection
- listener does not need send and receive buffers or an attention message buffer.
- The memory that you allocate becomes the property of ADSP when you call the
- dspCLInit command to establish a connection listener. You cannot write any data
- to this memory except through calls to ADSP, and you must ensure that the memory
- remains locked until you call the dspRemove command to eliminate the connection
- end. The connection control block is 242 bytes in size.
-
- 3. Call the dspCLInit command to establish a connection listener. You must
- provide a pointer to the connection control block.
-
- If there is a specific socket that you want to use for the connection listener,
- you can specify the socket number in the localSocket parameter. If you want ADSP
- to assign the socket for you, specify 0 for the localSocket parameter, and ADSP
- returns the socket number when the dspCLInit command completes execution.
-
- 4. If you wish, you can use the NBPRegister function to add the name and
- address of your connection listener to the node’s names table. The NBPRegister
- function is described in the AppleTalk Manager chapter of Volume II.
-
- 5. Use the dspCLListen command to cause the connection listener to wait for an
- open-connection request. Because the dspCLListen command does not complete
- execution until it receives a connection request, you should call this function
- asynchronously. You can specify a value for the filterAddress parameter to
- restrict the network number, node ID, or socket number from which you will
- accept an open-connection request.
-
- When the dspCLListen command receives an open-connection request that meets the
- restrictions of the filterAddress parameter, it returns a noErr result code (if
- you executed the function asynchronously, it places a noErr result code in the
- ioResult parameter) and places values in the parameter block for the remoteCID,
- remoteAddress, sendSeq, sendWindow, and attnSendSeq parameters.
-
- 6. If you want to open the connection, use the dspInit command to establish a
- connection end. You can use any available socket on the node for the connection
- end, including the socket that you used for the connection listener. Because a
- single socket can have more than one CCB connected with it, the socket can
- function simultaneously as a connection end and a connection listener.
-
- You can check the address of the remote socket to determine if it meets your
- criteria for a connection end. Although the filterAddress parameter to the
- dspCLListen command provides some screening of socket addresses, it cannot check
- for network number ranges, for example, or for a specific set of socket numbers.
- If for some reason you want to deny the connection request, call the DSPDeny
- function, specifying the connection control block of the connection listener in
- the ccbRefNum parameter. Because the dspCLListen command completes execution
- when it receives an open-connection request, you must return to step 5 to wait
- for another connection request.
-
- 7. Call the dspOpen command, specifying ocAccept for the ocMode parameter and
- specifying in the ccbRefNum parameter the reference number of the connection end
- that you want to use. When you call the dspOpen command , you must provide the
- values returned by the dspCLListen command for the remoteCID, remoteAddress,
- sendSeq, sendWindow, and attnSendSeq parameters.
-
- You can poll the state field in the connection control block to determine when
- the connection is open. The CCB is described in “The ADSP Connection Control
- Block” earlier in this chapter. Alternatively, you can check the result code for
- the dspOpen command when the function completes execution. If the function
- returns the noErr result code, then the connection is open.
-
- 8. You can now send and receive data and attention messages over the
- connection, as described in the preceding section, “Opening and Maintaining an
- ADSP Connection.” When you are ready to close the connection, you can use the
- dspClose or dspRemove commands, which are also described in the preceding
- section.
-
- 9. When you are finished using the connection listener, you can use the
- dspCLRemove command to eliminate it. Once you have called the dspCLRemove
- command, you can release the memory you allocated for the connection listener’s
- connection control block.
-
- Listing 29-3 illustrates the use of ADSP to establish and use a connection
- listener. It opens the .MPP and .DSP drivers, and allocates memory for the CCB.
- Then it uses the dspCLInit command to establish a connection listener, uses NBP
- to register the name of the connection end on the internet, and uses the
- dspCLListen command to wait for a connection request. When the routine receives
- a connection request, it calls the dspOpen command to complete the connection.
-
- Listing 29-3. Using ADSP to Establish and Use a Connection Listener (TO BE
- PROVIDED)
-
- _______________________________________________________________________________
-
- æKY Writing…a…User…Routine…For…Connection…Events
- æC »Writing a User Routine For Connection Events AppleTalk Manager
- _______________________________________________________________________________
-
- When you execute the dspInit command, you can specify a pointer to a routine
- that you provide (referred to as the user routine). Whenever an unsolicited
- connection event occurs, ADSP sets a flag in the connection control block (CCB)
- and calls the user routine. The user routine must clear the flag to acknowledge
- that it has read the flag field, and can then respond to the event in any manner
- you deem appropriate. The CCB flags are described in “The ADSP Connection
- Control Block” earlier in this chapter. There are four types of unsolicited
- connection events that set flags in the CCB, as follows:
-
- • ADSP has been informed by the remote connection end that the remote
- connection end is about to close the connection. An appropriate reponse
- might be to store a flag indicating that the connection end is about to
- close. When your application regains control, it can then display a
- dialog box informing the user of this event and asking whether the
- application should attempt to reconnect later.
-
- • ADSP has determined that the remote connection end is not responding, and
- so has closed the connection. Your user routine can attempt to open a new
- connection immediately. Alternatively, you can store a flag indicating
- that the connection has closed and, when your application regains
- control, it can display a dialog box asking the user whether to attempt
- to reconnect.
-
- • ADSP has received an attention message from the remote connection end.
- Depending on what you are using the attention message mechanism for, you
- might want to read the attention code in the attnCode field of the CCB
- and the attention message pointed to by the attnPtr field of the CCB.
-
- • ADSP has received a forward reset command from the remote client end, has
- discarded all ADSP data not yet delivered—including the data in the
- local client end’s receive queue—and has resynchronized the connection.
- Your response to this event depends on the purpose for which you are
- using the forward reset mechanism. You might want to resend the last data
- you have sent or inform the user of the event.
-
- When ADSP calls your user routine, the CPU is in interrupt-processing mode and
- register A1 contains a pointer to the CCB of the connection end that generated
- the event. You can examine the userFlags field of the CCB to determine what
- event caused the interrupt, and you can examine the state field of the CCB to
- determine the current state of the connection.
-
- Because the CPU is set to interrupt-processing mode, your user routine must
- preserve all registers other than A0, A1, D0, D1, and D2. Your routine must not
- make any direct or indirect calls to the Memory Manager, and can’t depend on
- handles to unlocked blocks being valid. If you want to use any of your
- application’s global variables, you must save the contents of the A5 register
- before using the variables, and you must restore the A5 register before your
- routine terminates. Listing 29-4 illustrates the use of the CCB to store the
- contents of the A5 register while your routine is executing.
-
- If you want to execute a routine each time an unsolicited connection event
- occurs but the interrupt environment is too restrictive, you can specify a NIL
- pointer to the user routine and periodically poll the userFlags field of the CCB
- instead.
-
- To ensure that you do not lose any attention messages, you must read any
- attention messages into an internal buffer before you clear the bit in the
- userFlags field.
-
- Listing 29-4 is an example of a user routine. When this routine is called, it
- first checks the connection control block to determine the source of the
- interrupt and then clears the bit in the userFlags field of the CCB. If the
- routine has received an attention message, the user routine reads the message
- into an internal buffer before it clears the flag bit.
-
- Listing 29-4. An ADSP user routine (TO BE PROVIDED)
- _______________________________________________________________________________
-
- æKY DSP…Driver…Commands
- æC »DSP Driver Commands AppleTalk Manager
- _______________________________________________________________________________
-
- The .DSP driver implements the AppleTalk Data Stream protocol (ADSP). You send
- commands to ADSP and obtain information about ADSP by executing the .DSP driver
- commands described in this section.
- To use a .DSP driver command, call PBControl passing a pointer to the .DSP
- parameter block as a parameter and the async parameter is a Boolean that
- specifies whether the function is to execute synchronously or asynchronously.
- Set the async parameter to TRUE to execute the function asynchronously.
-
- The .DSP parameter block is shown in “The .DSP Parameter Block” earlier in this
- chapter. The parameters used with each function are described in this section.
-
- For a general discussion of the use of ADSP, see “Using ADSP” earlier in this
- chapter.
-
- _______________________________________________________________________________
-
- æKY Establishing…and…Terminating…an…ADSP…Connection
- æC »Establishing and Terminating an ADSP Connection AppleTalk Manager
- _______________________________________________________________________________
-
- You can use the functions described in this section to
-
- • establish a connection end
- • open a connection
- • assign an identification number to a connection end
- • set the values for parameters that control the behavior of a connection
- end
- • close a connection end
- • eliminate a connection end
-
- The parameter block for the dspInit command looks like this:
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always dspInit
- ¨ 32 ccbRefNum word reference number for CCB
- Æ 34 ccbPtr long pointer to connection control block
- Æ 38 userRoutine long pointer to routine to call on
- connection events
- Æ 42 sendQSize word size in bytes of the send queue
- Æ 44 sendQueue long pointer to send queue
- Æ 48 recvQSize word size in bytes of the receive queue
- Æ 50 recvQueue long pointer to receive queue
- Æ 54 attnPtr long pointer to buffer for incoming
- attention messages
- ´ 58 localSocket byte DDP socket number for this
- connection end
-
- The dspInit command establishes a connection end; that is, it assigns a specific
- socket for use by ADSP and initializes the variables that ADSP uses to maintain
- the connection. The dspInit command does not open the connection end or
- establish a connection with a remote connection end; follow the dspInit command
- with the dspOpen command to perform those tasks. Use the dspCLInit command to
- establish a connection listener. Use the dspRemove command to eliminate a
- connection end.
-
- When you send bytes to a remote connection end, ADSP stores the bytes in a
- buffer called the send queue. It keeps the bytes you sent in the send queue
- until the remote connection end acknowledges their receipt, so that they are
- available to be retransmitted if necessary. When the local connection end
- receives bytes, it stores them in a buffer called the receive queue until you
- read them.
-
- You must allocate memory for the send and receive queues, and for a buffer that
- holds incoming attention messages. You must also allocate a nonrelocatable block
- of memory for the connection control block for this connection end.
-
- Note: When you use the dspInit command, the memory that you allocate becomes
- the property of ADSP. You cannot write any data to this memory except by calling
- ADSP routines, and you must ensure that the memory remains locked until you call
- the dspRemove command to eliminate the connection end.
-
- Parameters
-
- ioResult
- The result of the function. When you execute the function asynchronously, the
- function sets this parameter to 1 and returns a function result of noErr as soon
- as the function begins execution. When the function completes execution, it sets
- the ioResult parameter to the actual result code.
-
- csCode
- The routine selector, you should set this to dspInit for this command.
-
- ccbRefNum
- The reference number for the connection control block. The dspInit command
- returns this number. You must provide this number in all subsequent calls to
- this connection end.
-
- ccbPtr
- A pointer to the connection control block that you allocated. The connection
- control block is 242 bytes in size, and is described in “The ADSP Connection
- Control Block” earlier in this chapter.
-
- userRoutine
- A pointer to a routine that is to be called each time the connection end
- receives an unsolicited connection event. Specify NIL for this parameter if you
- do not want to supply a user routine. Connection events and user routines are
- discussed in “Writing a User Routine For Connection Events” earlier in this
- chapter.
-
- sendQSize
- The size in bytes of the send queue. A queue size of 600 bytes should work well
- for most applications. If you are using ADSP to send a continuous flow of data,
- a larger data buffer will improve performance. If your application is sending
- the user’s keystrokes, a smaller buffer should be adequate. The constant
- minDSPQueueSize indicates the minimum queue size that you can use.
-
-
- sendQueue
- A pointer to the send queue that you allocated.
-
- recvQSize
- The size in bytes of the receive queue. A queue size of 600 bytes should work
- well for most applications. If you are using ADSP to receive a continuous flow
- of data, a larger data buffer will improve performance. If your application is
- receiving a user’s keystrokes, a smaller buffer should be adequate. The constant
- minDSPQueueSize indicates the minimum queue size that you can use.
-
- recvQueue
- A pointer to the receive queue that you allocated.
-
- attnPtr
- A pointer to the attention-message buffer that you allocated. The
- attention-message buffer must be the size of the constant attnBufSize.
-
- localSocket
- The DDP socket number of the socket that you want ADSP to use for this
- connection end. Specify 0 for this parameter to cause ADSP to assign the socket.
- In the latter case, ADSP returns the socket number when the dspInit command
- completes execution.
-
- Result codes
- noErr 0 no error
- ddpSktErr –91 error opening socket
- errDSPQueueSize –1274 send or receive queue too small
-
- The parameter block for the dspOptions command looks like this:
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always dspOptions
- Æ 32 ccbRefNum word reference number of connection end
- Æ 34 sendBlocking word send-blocking threshold
- Æ 38 badSeqMax byte threshold to send retransmit advice
- Æ 39 useCheckSum byte use DDP checksum?
-
- The dspOptions command allows you to set values for several parameters that
- affect the behavior of the local connection end. You can set the options for any
- established connection end, whether open or not.
-
- Parameters
-
- ioResult
- The result of the function. When you execute the function asynchronously, the
- function sets this parameter to 1 and returns a function result of noErr as soon
- as the function begins execution. When the function completes execution, it sets
- the ioResult parameter to the actual result code.
-
- csCode
- The routine selector, you should set this to dspOptions for this command.
-
- ccbRefNum
- The connection control block reference number that was returned by the dspInit
- command.
-
- sendBlocking
- The maximum number of bytes that may accumulate in the send buffer before ADSP
- sends a packet to the remote connection end. ADSP sends a packet before the
- maximum number of bytes accumulates if the period specified by the send timer
- expires, if you execute the dspWrite command with the flush parameter set to 1,
- or if a connection event requires that the local connection end send an
- acknowledgement packet to the remote connection end.
-
- You can set the sendBlocking parameter to any value from 1 byte to the maximum
- size of a packet (572 bytes). If you set the sendBlocking parameter to 0, the
- current value for this parameter is not changed. The default value for the
- sendBlocking parameter is 16 bytes.
-
- badSeqMax
- The maximum number of out-of-sequence data packets that the local connection end
- can receive before requesting the remote connection end to retransmit the
- missing data. Because a connection end does not acknowledge the receipt of a
- data packet received out of sequence, the remote connection end’s retransmit
- timer will expire eventually and it will retransmit the data. The badSeqMax
- allows you to cause the data to be retransmitted before the remote connection
- end’s retransmit timer has expired.
-
- You can set the badSeqMax parameter to any value from 1 to 255. If you set the
- badSeqMax parameter to 0, the current value for this parameter is not changed.
- The default value for the badSeqMax parameter is 3.
-
- useCheckSum
- A flag specifying whether DDP should compute a checksum and include it in each
- packet that it sends to the remote connection end. Set this parameter to 1 to
- cause DDP to use checksums, or to 0 if you do not want DDP to use checksums. The
- default value for useCheckSum is 0.
-
- ADSP cannot include a checksum in a packet that has a short DDP header; that is,
- a packet being sent over LocalTalk to a remote socket that is on the same cable
- as the local socket. Note that the useCheckSum parameter affects only whether
- ADSP includes a checksum in a packet that it is sending. If ADSP receives a
- packet that includes a checksum, it validates the checksum regardless of the
- setting of the useCheckSum parameter.
-
- Result codes
- noErr 0 no error
- errRefNum –1280 bad connection reference number
-
- The parameter block for the dspOpen command looks like this:
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always dspOpen
- Æ 32 ccbRefNum word reference number of connection end
- ¨ 34 localCID word ID of this connection end
- ´ 36 remoteCID word ID of remote connection end
- ´ 38 remoteAddress long remote internet address
- Æ 42 filterAddress long filter for open connection requests
- ´ 46 sendSeq long initial send sequence number
- ´ 50 sendWindow word initial size of remote receive buffer
- Æ 52 recvSeq long initial receive sequence number
- ´ 56 attnSendSeq long attention send sequence number
- Æ 60 attnRecvSeq long attention receive sequence number
- Æ 64 ocMode byte connection opening mode
- Æ 65 ocInterval byte interval between open requests
- Æ 66 ocMaximum byte retries of open connection request
-
- You use the ocMode field of the parameter block to specify the opening mode that
- the dspOpen command is to use. The dspOpen command puts a connection end into
- one of four possible opening modes, as follows:
-
- • The ocRequest mode, in which ADSP attempts to open a connection with the
- socket at the internet address you specify with the remoteAddress
- parameter. If the socket you specify as a remote address is a connection
- listener, it is possible that your application will receive a connection
- acknowledgement and request from a different address than the one to
- which you sent the open-connection request. You can use the filterAddress
- parameter to restrict the addresses with which you will accept a
- connection.
-
- The dspOpen command completes execution in the ocRequest mode when either ADSP
- establishes a connection, your connection end receives a connection denial from
- the remote connection end, your connection end denies the connection request
- returned by a connection listener, or ADSP cannot complete the connection (ADSP
- has exceeded the maximum number of retries that you specified with the ocMaximum
- parameter).
-
- • The ocPassive mode, in which the connection end waits to receive an
- open-connection request from a remote connection end. You can use the
- filterAddress parameter to restrict the addresses from which you will
- accept a connection request.
-
- The dspOpen command completes execution in the ocPassive mode when ADSP
- establishes a connection or when either connection end receives a connection
- denial.
-
- • The ocAccept mode, used by connection servers to complete an
- open-connection dialog. When a connection server is informed by its
- connection listener that the connection listener has received an
- open-connection request, the connection server uses the dspInit command
- to establish a connection end and then calls the dspOpen command in
- ocAccept mode to complete the connection. You must obtain the following
- parameters from the dspCLListen command and provide them to the dspOpen
- command: remoteAddress, remoteCID, sendSeq, sendWindow, and attnSendSeq.
- Connection listeners and connection servers are described in “Creating
- and Using a Connection Listener,” earlier in this chapter, and in
- “Establishing and Terminating an ADSP Connection Listener,” later in this
- chapter.
-
- The dspOpen command completes execution in the ocAccept mode when ADSP
- establishes a connection or when either connection end receives a connection
- denial.
-
- • The ocEstablish mode, in which ADSP considers the connection end
- established and the connection state open. This mode is for use by
- clients that determine their connection-opening parameters without using
- ADSP or the .DSP driver to do so.
-
- You must first use the dspInit command to establish a connection end and then
- execute the dspNewCID command to obtain an identification number for the local
- connection end. You must then communicate with the remote connection end to send
- it the local connection ID and to determine the values of the following
- parameters: remoteAddress, remoteCID, sendSeq, sendWindow, recvSeq, attnSendSeq,
- and attnRecvSeq. Only then can you execute the dspOpen command in the
- ocEstablish mode.
-
- The dspOpen command completes execution in the ocEstablish mode immediately.
- The use of parameters by the dspOpen command depends on the mode in which the
- function is executed, as follows:
-
- ocRequest ocPassive ocAccept ocEstablish
-
- ¨ ioResult ¨ ioResult ¨ ioResult ¨ ioResult
- Æ csCode Æ csCode Æ csCode Æ csCode
- Æ ccbRefNum Æ ccbRefNum Æ ccbRefNum Æ ccbRefNum
- ¨ localCID ¨ localCID ¨ localCID — localCID
- ¨ remoteCID ¨ remoteCID Æ remoteCID Æ remoteCID
- Æ remoteAddress ¨ remoteAddress Æ remoteAddress Æ remoteAddress
- Æ filterAddress Æ filterAddress — filterAddress — filterAddress
- ¨ sendSeq ¨ sendSeq Æ sendSeq Æ sendSeq
- ¨ sendWindow ¨ sendWindow Æ sendWindow Æ sendWindow
- — recvSeq — recvSeq — recvSeq Æ recvSeq
- ¨ attnSendSeq ¨ attnSendSeq Æ attnSendSeq Æ attnSendSeq
- — attnRecvSeq — attnRecvSeq — attnRecvSeq Æ attnRecvSeq
- Æ ocMode Æ ocMode Æ ocMode Æ ocMode
- Æ ocInterval Æ ocInterval Æ ocInterval — ocInterval
- Æ ocMaximum Æ ocMaximum Æ ocMaximum — ocMaximum
-
- Parameters
-
- ioResult
- The result of the function. When you execute the function asynchronously, the
- function sets this parameter to 1 and returns a function result of noErr as soon
- as the function begins execution. When the function completes execution, it sets
- the ioResult parameter to the actual result code.
- csCode The routine selector, you should set this to dspOpen for this command.
-
- ccbRefNum
- The connection control block reference number that was returned by the dspInit
- command for the connection end that you want to use.
-
- localCID
- The identification number of the local connection end. This number is assigned
- by ADSP when the connection is opened. ADSP includes this number in every packet
- sent to a remote connection end. Before you call the dspOpen command in
- ocEstablish mode, you must call the dspNewCID command to cause ADSP to assign
- this value.
-
- remoteCID
- The identification number of the remote connection end. This parameter is
- returned by the dspOpen command in the ocRequest and ocPassive modes. A
- connection server must provide this number to the dspOpen command when the
- server executes the function in ocAccept mode; in this case, the connection
- server obtains the remoteCID value from the dspCLListen command. You must
- provide the remoteCID value to the dspOpen command when you use the function in
- ocEstablish mode.
-
- remoteAddress
- The internet address of the remote socket with which you wish to establish
- communications, consisting of a 2-byte network number, a 1-byte node ID, and a
- 1-byte socket number. You must provide this parameter when you call the dspOpen
- command in the ocRequest or ocEstablish modes. This parameter is returned by the
- dspOpen command when you call the function in the ocPassive mode. When you call
- the dspOpen command in the ocAccept mode, you must use the value for the
- remoteAddress parameter that was returned by the dspCLListen command.
- filterAddress The internet address of the socket from which you will accept a
- connection request. The address consists of three fields, a 2-byte network
- number, a 1-byte node ID, and a 1-byte socket number. Specify 0 for any of these
- fields for which you wish to impose no restrictions. If you specify a filter
- address of $00082500, for example, the connection end will accept a connection
- request from any socket at node $25 of network $0008. Set the filterAddress
- parameter equal to the remoteAddress parameter to accept a connection only with
- the socket to which you sent a connection request.
-
- When you execute the dspOpen command in the ocPassive mode, you can receive a
- connection request from any ADSP connection end on the internet. When you
- execute the dspOpen command in the ocRequest mode, your connection end can
- receive a connection request acknowledgment from an address different from the
- one you specified in the remoteAddress parameter only if the remote address you
- specified was that of a connection listener. in either case, you can use the
- filterAddress parameter to avoid acknowledging unwanted connection requests.
-
- When you execute the dspOpen command in the ocAccept mode, your connection
- listener has already received and decided to accept the connection request. You
- can specify a filter address for a connection listener with the dspCLListen
- command. A connection server can use the dspCLDeny command to deny a connection
- request that was accepted by its connection listener.
-
- You cannot use the filter address when you execute the dspOpen command in
- ocEstablish mode.
-
- sendSeq
- The sequence number of the first byte that the local connection end will send to
- the remote connection end. ADSP uses this number to coordinate communications
- and for error checking. ADSP returns a value for the sendSeq parameter when you
- execute the dspOpen command in the ocRequest or ocPassive modes. When you
- execute the dspOpen command in the ocAccept mode, you must specify the value for
- the sendSeq parameter that was returned by the dspCLListen command. You must
- provide the value for this parameter when you execute the dspOpen command in the
- ocEstablish mode.
-
- sendWindow
- The sequence number of the last byte that the remote connection end has buffer
- space to receive. ADSP uses this number to coordinate communications and for
- error checking. ADSP returns a value for the sendWindow parameter when you
- execute the dspOpen command in the ocRequest or ocPassive modes. When you
- execute the dspOpen command in the ocAccept mode, you must specify the value for
- the sendWindow parameter that was returned by the dspCLListen command. You must
- provide the value for this parameter when you execute the dspOpen command in the
- ocEstablish mode.
-
- recvSeq
- The sequence number of the next byte that the local connection end expects to
- receive. ADSP uses this number to coordinate communications and for error
- checking. You must provide the value for this parameter when you execute the
- dspOpen command in the ocEstablish mode. The dspOpen command does not use this
- parameter when you execute it in any other mode.
-
- attnSendSeq
- The sequence number of the next attention packet that the local connection end
- will transmit. ADSP uses this number to coordinate communications and for error
- checking. ADSP returns a value for the attnSendSeq parameter when you execute
- the dspOpen command in the ocRequest or ocPassive modes. When you execute the
- dspOpen command in the ocAccept mode, you must specify the value for the
- attnSendSeq parameter that was returned by the dspCLListen command. You must
- provide the value for this parameter when you execute the dspOpen command in the
- ocEstablish mode.
-
- attnRecvSeq
- The sequence number of the next attention packet that the local connection end
- expects to receive. ADSP uses this number to coordinate communications and for
- error checking. You must provide the value for this parameter when you execute
- the dspOpen command in the ocEstablish mode. The dspOpen command does not use
- this parameter when you execute it in any other mode.
-
- ocMode
- The mode in which the dspOpen command is to operate, as follows:
-
- Mode Value Meaning
- ocRequest 1 ADSP attempts to open a connection with the socket you
- specify
- ocPassive 2 The connection end waits to receive a connection request
- ocAccept 3 The connection server accepts and acknowledges receipt of a
- connection request
- ocEstablish 4 ADSP considers the connection established and open; you are
- responsible for setting up and synchronizing both connection ends
-
- ocInterval
- The period between transmissions of open-connection requests. If the remote
- connection end does not acknowledge or deny an open-connection request, ADSP
- retransmits the request after a time period specified by this parameter. The
- time period used by ADSP is (ocInterval ¥ 10) ticks; or (ocInterval /
- 6) seconds. For example, if you set the ocInterval parameter to 3, the time
- period between retransmissions is 30 ticks (1/2 second). You can set the
- ocInterval parameter to any value from 1 (1/6 second) to 180 (30 seconds). If
- you specify 0 for the ocInterval parameter, ADSP uses the default value of 6 (1
-
-
- You must provide a value for the ocInterval parameter when you execute the
- dspOpen command in the ocRequest, ocPassive, or ocAccept modes. The dspOpen
- command does not use this parameter when you execute it in the ocEstablish mode.
-
- ocMaximum
- The maximum number of times to retransmit an open-connection request before ADSP
- terminates execution of the dspOpen command. If you specify 0 for the ocMaximum
- parameter, ADSP uses the default value of 3. If you specify 255 for the
- ocMaximum parameter, ADSP retransmits the open-connection request indefinitely
- until the remote connection end either acknowledges or denies the request.
-
- You must provide a value for the ocMaximum parameter when you execute the
- dspOpen command in the ocRequest, ocPassive, or ocAccept modes. The dspOpen
- command does not use this parameter when you execute it in the ocEstablish mode.
-
- Result codes
- noErr 0 no error
- errOpening –1277 attempt to open connection failed
- errState –1278 connection end must be closed
- errAborted –1279 request aborted by dspRemove or dspClose command
- errRefNum –1280 bad connection reference number
-
- The parameter block for the dspNewCID command looks like this:
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always dspNewCID
- Æ 32 ccbRefNum word reference number of connection end
- ¨ 34 newCID word ID of new connection
-
- The dspNewCID command causes ADSP to assign an identification number to a
- connection end without opening the connection end or attempting to establish a
- connection with a remote connection end. Use this function only if you implement
- your own protocol to establish communications with a remote connection end. You
- must first use the dspInit command to establish a connection end. Next, you must
- call the dspNewCID command to obtain a connection-end ID. Then you must
- establish communication with a remote connection end and pass the ID to the
- remote connection end. Finally, you must call the dspOpen command in ocEstablish
- mode to cause ADSP to open the connection. See the description of the dspOpen
- command for more information on establishing a connection in this fashion.
-
- The ioResult parameter returns the result of the function; in the case that you
- call the function asynchronously, the function sets this field to 1 as soon as
- it begins execution, and changes the field to the actual result code when it
- completes execution. The csCode parameter is the routine selector; you should
- set this to dspNewCID for this command. The ccBRefNum parameter is the
- connection control block reference number that was returned by the dspInit
- command. The newCID parameter is the connection-end identification number
- returned by this function. You must provide this number to the client of the
- remote connection end so that it can use it for the remoteCID parameter when it
- calls the dspOpen command.
-
- Result codes
- noErr 0 no error
- errState –1278 connection is not closed
- errRefNum –1280 bad connection reference number
-
- The parameter block for the dspClose command looks like this:
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always dspClose
- Æ 32 ccbRefNum word reference number of connection end
- Æ 34 abort byte abort send requests if not 0
-
- The dspClose command closes the connection end. The connection end is still
- established; that is, ADSP retains ownership of the connection control block,
- send queue, receive queue, and attention-message buffer. You can continue to
- read bytes from the receive queue after you have called the dspClose command.
- Use the dspRemove command instead of the dspClose command if you are through
- reading bytes from the receive queue and want to release the memory associated
- with the connection end. The dspClose command does not return an error if you
- call it for a connection end that is already closed.
-
- The ioResult parameter returns the result of the function; in the case that you
- call the function asynchronously, the function sets this field to 1 as soon as
- it begins execution, and changes the field to the actual result code when it
- completes execution. The csCode parameter is the routine selector; you should
- set this to dspClose for this command. The ccBRefNum parameter is the connection
- control block reference number that was returned by the dspInit command. If the
- abort parameter is nonzero, ADSP cancels any outstanding requests to send data
- packets (such as the dspAttention command) and discards all data in the send
- queue. If the abort parameter is 0, ADSP does not close the connection end until
- all of the data in the send queue and all outstanding attention messages have
- been sent and acknowledged.
-
- Result codes
- noErr 0 no error
- errRefNum –1280 bad connection reference number
-
- The parameter block for the dspRemove command looks like this:
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always dspRemove
- Æ 32 ccbRefNum word reference number of connection end
- Æ 34 abort byte abort connection if not 0
-
- The dspRemove command closes any open connection and eliminates the connection
- end; that is, ADSP no longer retains control of the connection control block,
- send queue, receive queue, and attention-message buffer. You cannot continue to
- read bytes from the receive queue after you have called the dspRemove command.
- After you call the dspRemove command, you can release all of the memory you
- allocated for the connection end if you do not intend to reopen the connection
- end.
-
- The ioResult parameter returns the result of the function; in the case that you
- call the function asynchronously, the function sets this field to 1 as soon as
- it begins execution, and changes the field to the actual result code when it
- completes execution. The csCode parameter is the routine selector; you should
- set this to dspRemove for this command. The ccbRefNum parameter is the
- connection control block reference number that was returned by the dspInit
- command. If the abort parameter is nonzero, ADSP cancels any outstanding
- requests to send data packets (such as the dspAttention command) and discards
- all data in the send queue. If the abort parameter is 0, ADSP does not close the
- connection end until all of the data in the send queue has been sent and
- acknowledged.
-
- Result codes
- noErr 0 no error
- errRefNum –1280 bad connection reference number
- _______________________________________________________________________________
-
- æKY Establishing…and…Terminating…an…ADSP…Connection…Listener
- æC »Establishing and Terminating an ADSP Connection Listener AppleTalk Manager
- _______________________________________________________________________________
-
- A connection listener is a special kind of connection end that listens for
- open-connection requests from remote connection ends. Connection listeners are
- used by connection servers; that is, programs that assign a socket for the local
- connection end only after they receive a connection request from a remote
- connection end. A single connection listener, then, can receive connection
- requests from any number of remote connection ends.
-
- You can use the functions in this section to
-
- • establish a connection listener
- • cause the connection listener to wait for a connection request
- • deny a connection request
- • close and eliminate a connection listener
-
- The parameter block for the dspCLInit command looks like this:
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always dspCLInit
- ¨ 32 ccbRefNum word reference number of connection end
- Æ 34 ccbPtr long pointer to CCB
- ´ 58 localSocket byte local DDP socket number
-
- The dspCLInit command establishes a connection listener; that is, it assigns a
- specific socket for use by ADSP and initializes the variables that ADSP uses to
- maintain a connection listener. The dspCLInit command does not cause the
- connection listener to listen for connection requests; follow the dspCLInit
- command with the dspCLListen command to activate the connection listener. Use
- the dspInit command to establish a connection end that is not a connection
- listener. Use the dspCLRemove command to eliminate a connection listener.
-
- The ioResult parameter returns the result of the function; in the case that you
- call the function asynchronously, the function sets this field to 1 as soon as
- it begins execution, and changes the field to the actual result code when it
- completes execution. The csCode parameter is the routine selector; you should
- set this to dspCLInit for this command.The dspCLInit command returns the
- ccbRefNum parameter, which is the reference number for the connection control
- block. You must provide this number in all subsequent dspCLListen and
- dspCLRemove calls to this connection listener.
- You must allocate memory for a connection control block before you call the
- dspCLInit command. The ccbPtr parameter is a pointer to the connection control
- block that you allocated. The connection control block is 242 bytes, and is
- described in “The ADSP Connection Control Block” earlier in this chapter.
-
- The localSocket parameter is the DDP socket number of the socket that you want
- ADSP to use for this connection end. Specify 0 for this parameter to cause ADSP
- to assign the socket. In the latter case, ADSP returns the socket number when
- the dspCLInit command completes execution.
-
- Result codes
- noErr 0 no error
- ddpSktErr –91 error opening socket
-
- The parameter block for the dspCLListen command looks like this:
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always dspCLListen
- Æ 32 ccbRefNum word reference number of connection end
- ¨ 36 remoteCID word ID of remote connection end
- ¨ 38 remoteAddress long remote internet address
- Æ 42 filterAddress long filter for open connection requests
- ¨ 46 sendSeq long initial send sequence number
- ¨ 50 sendWindow word initial size of remote receive buffer
- ¨ 56 attnSendSeq long attention send sequence number
-
- The dspCLListen command causes a connection listener to listen for connection
- requests. You must have already used the dspCLInit command to establish a
- connection listener before using the dspCLListen command. The dspCLListen
- command is used only by connection servers.
-
- When ADSP receives an open-connection request from a socket that satisfies the
- address requirements of the filterAddress parameter, it returns values for the
- remoteCID, remoteAddress, sendSeq, sendWindow, and attnSendSeq parameters and
- completes execution of the dspCLListen command. You must then either accept the
- open-connection request by calling the dspOpen command in the ocAccept mode or
- deny the request by calling the dspCLDeny command.
-
- You can call the dspCLListen command several times, specifying the same
- connection listener. For example, if you wanted to accept connections from any
- or all of three different addresses, you could call the dspCLListen command
- three times with a different value for the filterAddress parameter each time.
- Note that you must execute the dspCLListen command asynchronously to take
- advantage of this feature.
-
- Parameters
-
- ioResult
- The result of the function. When you execute the function asynchronously, the
- function sets this parameter to 1 and returns a function result of noErr as soon
- as the function begins execution. When the function completes execution, it sets
- the ioResult parameter to the actual result code.
-
- csCode
- The routine selector; you should set this to dspCLListen for this command.
-
- ccbRefNum
- The connection control block reference number that was returned by the dspCLInit
- command.
-
- remoteCID
- The identification number of the remote connection end. You must pass this value
- to the dspOpen command when you open the connection or to the dspCLDeny command
- when you deny the connection request.
-
- remoteAddress
- The internet address of the remote socket that sent a request to open a
- connection. This address consists of a 2-byte network number, a 1-byte node ID,
- and a 1-byte socket number. You must pass this value to the dspOpen command when
- you open the connection or to the dspCLDeny command when you deny the connection
- request.
-
- filterAddress
- The internet address of the socket from which you will accept a connection
- request. The address consists of three fields, a 2-byte network number, a 1-byte
- node ID, and a 1-byte socket number. Specify 0 for any of these fields for which
- you wish to impose no restrictions. If you specify a filter address of
- $00082500, for example, the connection listener will accept a connection request
- from any socket at node $25 of network $0008.
-
- sendSeq
- The sequence number of the first byte that the local connection end will send to
- the remote connection end. ADSP uses this number to coordinate communications
- and for error checking. You must pass this value to the dspOpen command when you
- open the connection.
-
- sendWindow
- The sequence number of the last byte that the remote connection end has buffer
- space to receive. ADSP uses this number to coordinate communications and for
- error checking. You must pass this value to the dspOpen command when you open
- the connection.
-
- attnSendSeq
- The sequence number of the next attention packet that the local connection end
- will transmit. ADSP uses this number to coordinate communications and for error
- checking. You must pass this value to the dspOpen command when you open the
- connection.
-
- Result codes
- noErr 0 no error
- errState –1278 not a connection listener
- errAborted –1279 request aborted by the dspRemove command
- errRefNum –1280 bad connection reference number
-
- The parameter block for the dspCLDeny command looks like this:
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always dspCLDeny
- Æ 32 ccbRefNum word reference number of connection
- listener
- Æ 36 remoteCID word ID of remote connection end
- Æ 38 remoteAddress long remote internet address
-
- The dspCLDeny command is used by a connection server to inform a remote
- connection end that its request to open a connection cannot be honored.
-
- The ioResult parameter returns the result of the function; in the case that you
- call the function asynchronously, the function sets this field to 1 as soon as
- it begins execution, and changes the field to the actual result code when it
- completes execution. The csCode parameter is the routine selector; you should
- set this to dspCLDeny for this command. The ccbRefNum parameter is the reference
- number for the connection listener that received the connection request. This
- number is returned by the dspCLInit command when you establish a connection
- listener. The remoteCID and remoteAddress parameters specify the address and ID
- of the remote connection end. These parameters are returned by the dspCLListen
- command.
-
- Result codes
- noErr 0 no error
- errState –1278 not a connection listener
- errAborted –1279 request aborted by the dspRemove command
- errRefNum –1280 bad connection reference number
-
- The parameter block for the dspCLRemove command looks like this:
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always dspCLRemove
- Æ 32 ccbRefNum word reference number of connection
- listener
- Æ 34 abort byte abort connection listener if not 0
-
- The dspCLRemove command closes a connection end used as a connection listener.
- You can release the memory you allocated for the connection control block if you
- do not intend to reopen the connection end.
-
- The ioResult parameter returns the result of the function; in the case that you
- call the function asynchronously, the function sets this field to 1 as soon as
- it begins execution, and changes the field to the actual result code when it
- completes execution. The csCode parameter is the routine selector; you should
- set this to dspCLRemove for this command. The ccbRefNum parameter is the
- connection control block reference number that was returned by the dspCLInit
- command. If the abort parameter is nonzero, ADSP cancels any outstanding
- requests to send packets (such as the dspCLDeny command).
-
- Result codes
- noErr 0 no error
- errRefNum –1280 bad connection reference number
- _______________________________________________________________________________
-
- æKY Maintaining…an…ADSP…Connection
- æC »Maintaining an ADSP Connection AppleTalk Manager
- _______________________________________________________________________________
-
- Once you have established a connection end and opened a connection, you must be
- able to send and receive data over the connection. You can use the functions in
- this section to
-
- • determine the status of a connection
- • read bytes from the connection end’s receive queue
- • write bytes to the connection end’s send queue and transmit them to the
- remote connection end
- • send an attention message to the remote connection end
- • discard all data that has been sent but not yet delivered, and reset the
- connection
-
- The parameter block for the dspStatus command looks like this:
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always dspStatus
- Æ 32 ccbRefNum word reference number of connection end
- ¨ 34 statusCCB pointer pointer to connection control block
- ¨ 38 sendQPending word bytes waiting to be sent or
- acknowledged
- ¨ 40 sendQFree word available send queue in bytes
- ¨ 42 recvQPending word bytes waiting to be read from queue
- ¨ 44 recvQFree word available receive queue in bytes
-
- The dspStatus command returns the number of bytes waiting to be read and sent
- and the space available in the send and receive queues. This function also
- returns a pointer to the connection control block, which contains information
- about the state of the connection end and about connection events received by
- the connection end. The connection control block is described in “The ADSP
- Connection Control Block” earlier in this chapter.
-
- The ioResult parameter returns the result of the function; in the case that you
- call the function asynchronously, the function sets this field to 1 as soon as
- it begins execution, and changes the field to the actual result code when it
- completes execution. The csCode parameter is the routine selector; you should
- set this to dspStatus for this command. The ccbRefNum parameter is the
- connection control block reference number that was returned by the dspInit
- command. The statusCCB parameter returns a pointer to the connection control
- block.
-
- The sendQPending parameter indicates the number of bytes of data in the send
- queue, including one byte for each end-of-message (EOM) indicator in the send
- queue. (ADSP counts one byte for each EOM, even though there is no actual data
- corresponding to the end-of-message indicator.) The send queue contains all data
- that has been sent to ADSP for transmission that has not yet been acknowledged.
- Some of the data in the send queue might have already been transmitted, but ADSP
- retains it in the send queue until the remote connection end acknowledges its
- receipt in case the data has to be retransmitted. The sendQFree parameter
- indicates the buffer space available for additional data in the send queue, in
- bytes.
-
- The recvQPending parameter indicates the number of bytes in the receive queue,
- including one byte for each EOM if the end-of-message bit is set in an ADSP
- packet header. The receive queue contains all of the data that has been received
- by the connection end but not yet read by the connection end’s client. The
- recvQFree parameter indicates the buffer space available for additional data in
- the receive queue, in bytes.
-
- Result codes
- noErr 0 no error
- errRefNum –1280 bad connection reference number
-
- The parameter block for the dspRead command looks like this:
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always dspRead
- Æ 32 ccbRefNum word reference number of connection end
- Æ 34 reqCount word requested number of bytes
- ¨ 36 actCount word actual number of bytes read
- Æ 38 dataPtr pointer pointer to data buffer
- ¨ 42 eom byte 1 if end-of-message; 0 otherwise
-
- The dspRead command reads bytes from the connection end’s receive queue and
- places them in a buffer that you specify. You can continue to read bytes as long
- as there is data in the receive queue, even after you or the remote end have
- called the dspClose or dspRemove commands. The dspRead command completes
- execution when it has read the number of bytes you specify, or when it
- encounters an end-of-message (that is, the last byte of data in an ADSP packet
- that has the end-of-message bit set in the packet header).
-
- You can call the dspStatus command to determine the number of bytes remaining to
- be read from the read queue, or you can continue to call the dspRead command
- until the actCount and eom parameters both return 0.
-
- The ioResult parameter returns the result of the function; in the case that you
- call the function asynchronously, the function sets this field to 1 as soon as
- it begins execution, and changes the field to the actual result code when it
- completes execution. The csCode parameter is the routine selector; you should
- set this to dspRead for this command. The ccbRefNum parameter is the connection
- control block reference number that was returned by the dspInit command.
- You specify the number of bytes to read with the reqCount parameter, and use the
- dataPtr parameter to provide a pointer to the buffer into which ADSP should
- place the data. ADSP returns the actual number of bytes read in the actCount
- parameter. If the last byte read constitutes an end-of-message, ADSP sets the
- eom parameter to 1.
-
- Result codes
- noErr 0 no error
- errFwdReset –1275 read terminated by forward reset
- errState –1278 state isn’t open, closing, or closed
- errAborted –1279 request aborted by dspRemove or dspClose command
- errRefNum –1280 bad connection reference number
-
- The parameter block for the dspWrite command looks like this:
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always dspWrite
- Æ 32 ccbRefNum word reference number of connection end
- Æ 34 reqCount word requested number of bytes
- ¨ 36 actCount word actual number of bytes written
- Æ 38 dataPtr pointer pointer to data buffer
- Æ 42 eom byte 1 if end of message; 0 otherwise
- Æ 43 flush byte 1 to send data now; 0 otherwise
-
- The dspWrite command writes bytes into the connection end’s send queue. The send
- queue contains all data that has been sent to ADSP for transmission that has not
- yet been acknowledged. Some of the data in the send queue might have already
- been transmitted, but ADSP retains it in the send queue until the remote
- connection end acknowledges its receipt in case the data has to be
- retransmitted. The dspWrite command completes execution when it has copied all
- of the data from the data buffer into the ADSP send queue.
-
- ADSP transmits the data in the send queue when the remote connection end has
- room to accept the data and one of the following conditions occurs:
-
- • You call the dspWrite command with the flush parameter set to a nonzero
- number.
-
- • The number of bytes in the send queue equals or exceeds the blocking
- factor; you use the sendBlocking parameter to the dspOptions command to
- set the blocking factor.
-
- • The send timer expires.
-
- • A connection event requires that the local connection end send an
- acknowlegment packet to the remote connection end.
-
- The ioResult parameter returns the result of the function; in the case that you
- call the function asynchronously, the function sets this field to 1 as soon as
- it begins execution, and changes the field to the actual result code when it
- completes execution. The csCode parameter is the routine selector; you should
- set this to dspWrite for this command. The ccbRefNum parameter is the connection
- control block reference number that was returned by the dspInit command.
-
- You specify the number of bytes to write with the reqCount parameter, and use
- the dataPtr parameter to provide a pointer to the buffer from which ADSP should
- read the data. The dspWrite command returns the actual number of bytes written
- in the actCount parameter. If the last byte written constitutes an
- end-of-message, set the eom parameter to 1. You can also set the reqCount
- parameter to 0 and the eom parameter to 1 to indicate that the last byte you
- sent the previous time you called the dspWrite command was the end of the
- message.
-
- You can set the reqCount parameter to a value larger than the size of the send
- queue. If you do so, the dspWrite command writes as much data as it can into the
- send queue, sends the data and waits for acknowledgement, and then writes more
- data into the send queue until it has written the amount of data you requested.
- In this case, the function does not complete execution until it has finished
- writing all of the data into the send queue.
-
- The high-order bits of the eom parameter are reserved for use by ADSP; you must
- leave these bits equal to 0.
-
- Set the flush parameter to 1 to cause ADSP to immediately transmit any data in
- the send queue that has not already been transmitted. Set the flush parameter to
- 0 to allow data to accumulate in the send queue until another condition occurs
- that causes data to be transmitted. The high-order bits of the flush parameter
- are reserved for use by ADSP; you must leave these bits equal to 0.
-
- Result codes
- noErr 0 no error
- errState –1278 connection is not open
- errAborted –1279 request aborted by dspRemove or dspClose command
- errRefNum –1280 bad connection reference number
-
- The parameter block for the dspAttention command looks like this:
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always dspAttention
- Æ 32 ccbRefNum word reference number of connection end
- Æ 34 attnCode word client attention code
- Æ 36 attnSize word size of attention data in bytes
- Æ 38 attnData pointer pointer to attention data
-
- The dspAttention command sends an attention code and an attention message to the
- remote connection end. Attention codes and attention messages can have any
- meaning that your application and the application at the remote connection end
- both recognize. The purpose of attention codes and messages is to allow clients
- of ADSP to send messages outside the normal data stream. For example, if a
- connection end on a mainframe computer is connected to several connection ends
- in Macintosh computers being used as remote terminals, the mainframe computer
- might wish to inform the remote terminals that all connections will be
- terminated in ten minutes. The mainframe application could send an attention
- message to each of the remote terminals informing them of this fact, and the
- terminal emulation programs in the Macintosh computers could then display an
- alert message on the screen so that the users could prepare to shut down.
-
- The ioResult parameter returns the result of the function; in the case that you
- call the function asynchronously, the function sets this field to 1 as soon as
- it begins execution, and changes the field to the actual result code when it
- completes execution. The csCode parameter is the routine selector; you should
- set this to dspAttention for this command. The ccbRefNum parameter is the
- connection control block reference number that was returned by the dspInit
- command.
-
- The attnCode parameter is the attention code that you wish to send to the remote
- connection end. You can use any value from $0000 through $EFFF for the attention
- code. The values $F000 through $FFFF are reserved for use by ADSP. The attnSize
- parameter is the size in bytes of the attention message you wish to send, and
- the attnData parameter provides a pointer to the attention message. The
- attention message can be any size from 0 through 570 bytes. There are no
- restrictions on the content of the attention message.
-
- Result codes
- noErr 0 no error
- errAttention –1276 attention message too long
- errState –1278 connection is not open
- errAborted –1279 request aborted by dspRemove or dspClose command
- errRefNum –1280 bad connection reference number
-
- The parameter block for the dspReset command looks like this:
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always dspReset
- Æ 32 ccbRefNum word reference number of connection end
-
- The dspReset command causes ADSP to discard all data in the send queue, all data
- in transit to the remote connection end, and all data in the remote connection
- end’s receive queue that the client has not yet read. This process is known as a
- forward reset. ADSP then resynchronizes the connection. You can determine that
- your connection end has received a forward reset and has discarded all data in
- the receive queue by checking the eFwdReset flag in the userFlags field of the
- connection control block. The connection control block is described in “The ADSP
- Connection Control Block” earlier in this chapter.
-
- The ioResult parameter returns the result of the function; if you call the
- function asynchronously, the function sets this field to 1 as soon as it begins
- execution, and changes the field to the actual result code when it completes
- execution. The csCode parameter is the routine selector; you should set this to
- dspReset for this command. The ccbRefNum parameter is the connection control
- block reference number that was returned by the dspInit command.
-
- Result codes
- noErr 0 no error
- errState –1278 connection is not open
- errAborted –1279 request aborted by dspRemove or dspClose command
- errRefNum –1280 bad connection reference number
- _______________________________________________________________________________
-
- æKY The….ATP…Driver
- æC »THE .ATP DRIVER AppleTalk Manager
- _______________________________________________________________________________
-
- AppleTalk Phase 2 includes two changes to the .ATP driver: you can now cancel
- all calls to the ATPGetRequest function that are pending execution, and you can
- now set the release timer for ATP exactly-once (XO) service to one of five
- different values.
- _______________________________________________________________________________
-
- æKY Canceling…All…Calls…to…the…ATPGetRequest…Function
- æC »Canceling All Calls to the ATPGetRequest Function AppleTalk Manager
- _______________________________________________________________________________
-
- The ATPGetRequest function sets a socket to receive a request sent by another
- socket. If you call the ATPGetRequest function asynchronously, you can have
- several calls to the function simultaneously pending execution. The
- ATPKillAllGetReq function cancels all calls to the ATPGetRequest function
- pending for a specific socket without closing the socket.
-
- FUNCTION ATPKillAllGetReq (thePBptr: ATPPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- Æ 26 csCode word always ATPKillAllGetReq
- Æ 28 atpSocket byte socket for which to cancel all calls to ATPGetRequest
-
- The ATPKillAllGetReq function cancels all pending asynchronous calls to the
- ATPGetRequest function for the socket you specify with the atpSocket parameter.
- Unlike the ATPCloseSocket function, the ATPKillAllGetReq function does not close
- the socket. You should call the ATPKillAllGetReq function before closing a
- socket. The csCode parameter is a routine selector, automatically set by the MPW
- interface. It is always equal to ATPKillAllGetReq for this function.
-
- Result codes
- noErr 0 no error
- cbNotFound –1102 control block not found; no pending asynchronous calls
- _______________________________________________________________________________
-
- æKY Setting…the…Timeout…Value…For…the…ATP…Release…Timer
- æC »Setting the Timeout Value For the ATP Release Timer AppleTalk Manager
- _______________________________________________________________________________
-
- The .ATP driver maintains a timer, called the release timer, for each call to
- the PSendResponse function that is part of an exactly-once transaction. If the
- timer expires before the transaction is complete (that is, before the socket
- receives the transaction release packet), the driver completes the PSendResponse
- function. Before AppleTalk Phase 2, the release timer was always set to 30
- seconds. To set the other connection end’s release timer to another value, set
- bit 2 of the atpFlags field in the parameter block for the PSendRequest or the
- PNSendRequest function and add a new field to the parameter block at offset 50:
- the TRelTime field. The lower three bits of the TRelTime field indicate the time
- to which the release timer is to be set, as follows:
-
- TRelTime Field Setting of Release Timer
- 000 30 seconds
- 001 1 minute
- 010 2 minutes
- 011 4 minutes
- 100 8 minutes
-
- Note: The nodes at both ends of the ATP connection must be running AppleTalk
- Phase 2 drivers for this feature to work.
-
- Exactly-once service, the release timer, and the PSendRequest function are
- described in the AppleTalk Manager chapter of Volume II. The ATP parameter block
- and the PSendRequest function are described in the AppleTalk Manager chapter of
- Volume V.
-
- _______________________________________________________________________________
-
- æKY The….XPP…Driver
- æC »THE .XPP DRIVER AppleTalk Manager
- _______________________________________________________________________________
-
- The .XPP driver provides these functions that return information about zones:
-
- • The GetMyZone function returns the AppleTalk zone name of the node on
- which your application is running.
-
- • The GetLocalZones function returns a list of zone names on the network
- that includes the node on which your application is running.
-
- • The GetZoneList function returns a complete list of zones on the internet.
-
- Note: Before the AppleTalk Phase 2 version of the .XPP driver, you had to use
- ATP to obtain zone information and request it directly from a router. The ZIP
- functions provided by the new version of the .XPP driver make it much easier for
- you to obtain this information. To ensure compatibility with future versions of
- AppleTalk, you should always use the functions described in this section to
- obtain zone information.
-
- The .XPP driver uses a parameter block defined by the xCallParam record for the
- GetMyZone, GetLocalZones, and GetZoneList functions.
-
- xCallParam = PACKED RECORD
- qLink: QElemPtr; {next queue entry}
- qType: INTEGER; {queue type}
- ioTrap: INTEGER; {routine trap}
- ioCmdAddr: Ptr; {routine address}
- ioCompletion: ProcPtr; {completion routine}
- ioResult: OsErr; {result code}
- ioNamePtr: StringPtr;{used only for Open routine}
- ioVRefNum: INTEGER; {volume reference number}
- ioRefNum: INTEGER; {driver reference number}
- csCode: INTEGER; {primary command code}
- xppSubCode: INTEGER; {secondary command code}
- xppTimeOut: Byte; {timeout period for .XPP}
- xppRetry: Byte; {retry count}
- filler: INTEGER; {reserved}
- zipBuffPtr: Ptr; {returned zone names}
- zipNumZones: INTEGER; {number of zones returned}
- zipLastFlag: Byte; {nonzero when all zone names have been returned}
- filler Byte; {reserved}
- zipInfoField: PACKED ARRAY[1..70] of Byte {reserved for use by .XPP}
- END;
-
- XCallParamPtr = ^XCallParam;
-
- As for all other AppleTalk Manager preferred interface functions, the MPW
- interface calls the Device Manager PBControl function to implement these ZIP
- protocol functions. The qLink, qType, ioTrap, ioCmdAddr, ioNamePtr, and
- ioVRefNum fields are filled in by the Device Manager; your application should
- not have to set or read these parameters. The ioResult parameter returns the
- result of the function; in the case that you call the function asynchronously,
- the Device Manager sets this field to 1 as soon as you call the function, and
- changes the field to the actual result code when the function completes
- execution. The ioCompletion parameter is a pointer to a completion routine that
- you can provide; the Device Manager calls your completion routine when it
- completes execution of the PBControl function. If you are not providing a
- completion routine, specify NIL for this field. The ioRefNum, csCode, and
- xppSubCode fields specify the driver and the command to be executed; the MPW
- Pascal interface fills in these fields for you.
-
- _______________________________________________________________________________
-
- æKY Using…the….XPP…Driver…to…Obtain…Zone…Information
- æC »Using the .XPP Driver to Obtain Zone Information AppleTalk Manager
- _______________________________________________________________________________
-
- The Zone Information Protocol obtains the zone information by using the
- AppleTalk Transaction Protocol to send an information request to a router. The
- xppTimeOut field specifies the amount of time, in seconds, that the .ATP driver
- should wait between attempts to obtain the data. The xppRetry field specifies
- the number of times the .ATP driver should attempt to obtain the data before
- returning the reqFailed (request failed) result code.
-
- The zipBuffPtr field is a pointer to a data buffer that you must allocate. This
- buffer must be 578 bytes for the GetZoneList and GetLocalZones functions and 33
- bytes for the GetMyZone function. The Zone Information Protocol returns the zone
- names (as a packed array of packed Pascal strings) into this buffer. The
- zipNumZones field returns the actual number of zone names that ZIP placed in the
- buffer. You must set the zipLastFlag field to 0 before you execute the
- GetZoneList or GetLocalZones functions. If the zipLastFlag parameter is still 0
- when the command has completed execution, then the ZIP is waiting to return more
- zone names. In this case you must empty the buffer (or allocate a new one) and
- call the GetZoneList or GetLocalZones function again immediately. When there are
- no more zone names to send, ZIP sets the zipLastFlag field to a nonzero value.
-
- The zipInfoField field is a 70-byte data buffer that you must allocate for use
- by the .XPP driver. The first time you call any of these functions, you must set
- the first word of this field to 0. You must not change any values in this field
- subsequently.
-
- Listing 29-5 illustrates the use of the GetZoneList function. The GetLocalZones
- function operates in exactly the same fashion.
-
- Listing 29-5. Using the GetZoneList function (TO BE PROVIDED)
-
- Listing 29-6 illustrates the use of the GetMyZone function.
-
- Listing 29-6. Using the GetMyZone function (TO BE PROVIDED)
- _______________________________________________________________________________
-
- æKY XPP…Driver…Routines
- æC »XPP Driver Routines AppleTalk Manager
- _______________________________________________________________________________
-
- The .XPP driver provides three functions that obtain information about zones.
- All three functions use the Zone Information Protocol to return the names of
- zones: The GetMyZone function returns the AppleTalk zone name of the node on
- which your application is running; the GetLocalZones function returns a list of
- zone names on the network that includes the node on which your application is
- running; and the GetZoneList function returns a complete list of zones on the
- internet.
-
- Assembly-language note: The .XPP driver functions all use the same value
- (xCall, which is equal to 246) for the csCode parameter to the xCallParam
- parameter block. The xCall routine uses the value of the xppSubCode parameter to
- distinguish between the functions, as follows:
-
- Function xppSubCode Value
- GetMyZone getMyZone 7
- GetLocalZones getLocalZones 5
- GetZoneList getZoneList 6
-
- FUNCTION GetMyZone (thePBptr:XCallParamPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word routine selector; always xCall
- Æ 28 xppSubCode word routine selector; getMyZone
- Æ 30 xppTimeOut byte retry interval in seconds
- Æ 31 xppRetry byte retry count
- Æ 34 zipBuffPtr long pointer to data buffer
- Æ 42 zipInfoField 70 bytes for use by ZIP; first word set to 0
-
- The GetMyZone function returns only the zone name of the node on which your
- application is running.
-
- The ioResult parameter returns the result of the function; if you call the
- function asynchronously, the function sets this field to 1 as soon as it begins
- execution, and changes the field to the actual result code when it completes
- execution. The csCode and xppSubCode parameters are routine selectors and are
- automatically set by the MPW interface to xCall and getMyZone for this function.
- The xppTimeOut field specifies the amount of time, in seconds, that the .ATP
- driver should wait between attempts to obtain the data. A value of 3 or 4 for
- the xppTimeOut field generally gives good results. The xppRetry field specifies
- the number of times the .ATP driver should attempt to obtain the data before
- returning the ReqFailed (request failed) result code. A value of 3 or 4 for the
- xppRetry field usually works well.
-
- The zipBuffPtr is a pointer to a 33-byte data buffer that you must allocate. The
- Zone Information Protocol returns the zone name into this buffer as a Pascal
- string. The zipInfo field is a 70-byte data buffer that you must allocate for
- use by ZIP. You must set the first word of this buffer to 0 before you call the
- GetMyZone function.
-
- Result codes
- noErr 0 no error
- noBridgeErr –93 no router is available
- reqFailed –1096 Request to contact router failed; retry count exceeded
-
- FUNCTION GetLocalZones (thePBptr:XCallParamPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word routine selector; always xCall
- Æ 28 xppSubCode word routine selector; getLocalZones
- Æ 30 xppTimeOut byte retry interval in seconds
- Æ 31 xppRetry byte retry count
- Æ 34 zipBuffPtr pointer pointer to data buffer
- ¨ 38 zipNumZones word number of names returned
- ¨ 40 zipLastFlag byte nonzero if no more names
- Æ 42 zipInfoField 70 bytes for use by ZIP; first word set to 0
-
- The GetLocalZones function returns a list of all the zone names on the local
- network; that is, the network that includes the node on which your application
- is running.
-
- The ioResult parameter returns the result of the function; if you call the
- function asynchronously, the function sets this field to 1 as soon as it begins
- execution, and changes the field to the actual result code when it completes
- execution. The csCode and xppSubCode parameters are routine selectors and are
- automatically set by the MPW interface to xCall and getLocalZones for this
- function. The xppTimeOut field specifies the amount of time, in seconds, that
- the .ATP driver should wait between attempts to obtain the data. A value of 3 or
- 4 for the xppTimeOut field generally gives good results. The xppRetry field
- specifies the number of times the .ATP driver should attempt to obtain the data
- before returning the ReqFailed (request failed) result code. A value of 3 or 4
- for the xppRetry field usually works well.
-
- The zipBuffPtr is a pointer to a 578-byte data buffer that you must allocate.
- The Zone Information Protocol returns the zone names into this buffer as a
- packed array of packed Pascal strings. The zipNumZones parameter returns the
- number of zone names that ZIP placed in the data buffer.
-
- The .XPP driver sets the zipLastFlag field to 1 if there are no more zone names
- for your network. If the zipLastFlag field is still 0 when the GetLocalZones
- function has completed execution, you must empty the data buffer pointed to by
- the zipBuffPtr parameter and immediately call the GetLocalZones function again
- without changing the value in the zipInfoField parameter. The zipInfofield
- parameter is a 70-byte data buffer that you must allocate for use by ZIP. You
- must set the first word of this buffer to 0 before you call the GetLocalZones
- function the first time, and not change the contents of this field thereafter.
-
- FUNCTION GetZoneList (thePBptr:XCallParamPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word routine selector; always xCall
- Æ 28 xppSubCode word routine selector; getZoneList
- Æ 30 xppTimeOut byte retry interval in seconds
- Æ 31 xppRetry byte retry count
- Æ 34 zipBuffPtr pointer pointer to data buffer
- ¨ 38 zipNumZones word number of names returned
- ¨ 40 zipLastFlag byte nonzero if no more names
- Æ 42 zipInfoField 70 bytes for use by ZIP; first word set to 0
-
- The GetZoneList function returns a complete list of all the zone names on the
- internet. Use the GetLocalZones function to obtain a list of only the zone names
- on the local network.
-
- The ioResult parameter returns the result of the function; if you call the
- function asynchronously, the function sets this field to 1 as soon as it begins
- execution, and changes the field to the actual result code when it completes
- execution. The csCode and xppSubCode parameters are routine selectors and are
- automatically set by the MPW interface to xCall and getZoneList for this
- function. The xppTimeOut field specifies the amount of time, in seconds, that
- the .ATP driver should wait between attempts to obtain the data. A value of 3 or
- 4 for the xppTimeOut field generally gives good results. The xppRetry field
- specifies the number of times the .ATP driver should attempt to obtain the data
- before returning the ReqFailed (request failed) result code. A value of 3 or 4
- for the xppRetry field usually works well.
-
- The zipBuffPtr is a pointer to a 578-byte data buffer that you must allocate.
- The Zone Information Protocol returns the zone names into this buffer as Pascal
- strings. The zipNumZones parameter returns the number of zone names that ZIP
- placed in the data buffer.
-
- The .XPP driver sets the zipLastFlag field to 1 if there are no more zone names
- for the internet. If the zipLastFlag field is still 0 when the GetZoneList
- function has completed execution, you must empty the data buffer pointed to by
- the zipBuffPtr parameter and immediately call the GetZoneList function again
- without changing the value in the zipInfoField parameter. The zipInfofield
- parameter is a 70-byte data buffer that you must allocate for use by ZIP. You
- must set the first word of this buffer to 0 before you call the GetZoneList
- function the first time, and not change the contents of this field thereafter.
-
- _______________________________________________________________________________
-
- æKY The….ENET…Driver
- æC »THE .ENET DRIVER AppleTalk Manager
- _______________________________________________________________________________
-
- The .ENET driver is an Ethernet driver for the EtherTalk NuBus card that is
- manufactured by Apple Computer, Inc. The .ENET driver is normally called by the
- AppleTalk Manager through the EtherTalk 'adev' file when the user has selected
- EtherTalk from the Network control panel. You can write your own protocol stack
- or application that uses the .ENET driver directly, rather than through
- AppleTalk. This section describes how to open the .ENET driver, how to send data
- to it directly for transmission over the Ethernet network, and how to write a
- protocol handler to receive data from the network.
-
- If you write an Ethernet driver for use with your own Ethernet NuBus card, you
- should provide the features and functions described in this chapter and should
- name your driver .ENET. If you write an Ethernet driver for use with a non-NuBus
- network interface (such as an Ethernet card for the Macintosh SE/30 or an
- Ethernet connection through the SCSI port), you should provide the features and
- functions described in this chapter for the .ENET driver and should name your
- driver .ENET0. If you do so, any software written to use the .ENET driver should
- work with your driver.
-
- _______________________________________________________________________________
-
- æKY Changing…the…Ethernet…Hardware…Address
- æC »Changing the Ethernet Hardware Address AppleTalk Manager
- _______________________________________________________________________________
-
- Each Ethernet NuBus card or other Ethernet hardware interface device contains a
- unique 6-byte hardware address assigned by the manufacturer of the device. The
- .ENET driver normally uses this address to determine whether to receive a
- packet. To change the hardware address for your node, place in the System file a
- resource of type 'eadr' with a resource ID equal to the slot number of the
- Ethernet NuBus card. If the Ethernet device is not a NuBus card (it might be a
- slot card in a Macintosh SE/30, for example), use a resource ID of 0.
-
- The 'eadr' resource consists only of a 6-byte number. Do not use the broadcast
- address or a multicast address for this number. (The broadcast address is
- $FF-FF-FF-FF-FF-FF. A multicast address is any Ethernet address in which the
- low-order bit of the high-order byte is set to 1.) When you open the .ENET
- driver, it looks for an 'eadr' resource. If it finds one, the driver substitutes
- the number in this resource for the Ethernet hardware address and uses it until
- the driver is closed or reset.
-
- Note: To avoid address collisions, you should never arbitrarily change the
- Ethernet hardware address. This feature should be used only by a system
- adiministrator who can keep track of all the Ethernet addresses in the system.
-
- _______________________________________________________________________________
-
- æKY Opening…the….ENET…Driver
- æC »Opening the .ENET Driver AppleTalk Manager
- _______________________________________________________________________________
-
- Before you use the OpenSlot function to open the .ENET driver, you must
- determine which NuBus slots contain EtherTalk cards. The OpenSlot function is
- described in the Device Manager chapter of Volume V. Use the GetsRsrc function
- described in the Slot Manager chapter of this volume to determine which NuBus
- slots contain cards and the type of each NuBus card installed. EtherTalk NuBus
- cards return the string CatNetwork in the field spCategory of the GetsRsrc
- function parameter block, and return the string TypEthernet in the field spType.
-
- Listing 29-7 illustrates the use of the GetsRsrc function and the OpenSlot
- function to open the .ENET driver.
-
- Listing 29-7. Finding an EtherTalk card and opening the .ENET Driver (TO BE
- PROVIDED)
- _______________________________________________________________________________
-
- æKY Using…a…Write-Data…Structure…to…Transmit…Ethernet…Data
- æC »Using a Write-Data Structure to Transmit Ethernet Data AppleTalk Manager
- _______________________________________________________________________________
-
- When you use the EWrite function to send data to the .ENET driver for
- transmission over the Ethernet network, you provide a pointer to a write-data
- structure (Figure 29-4). A write-data structure contains a series of pairs of
- length words and pointers. Each pair indicates the length and location of a
- portion of the data that constitutes the packet to be sent over the network. The
- first length-pointer pair points to a 14-byte header block, which starts with
- the destination node hardware address. Note that this is not the AppleTalk
- address, but is the hardware address of the destination node. If you are calling
- the .ENET driver directly, you must obtain the Ethernet address of the
- destination node yourself; AppleTalk cannot provide it.
-
- The next 6 bytes of the header block are reserved for use by the .ENET driver.
- These bytes are followed by the 2-byte Ethernet protocol type. Data may follow
- the header block; all other length-pointer pairs point to data. The write-data
- structure terminates with a NIL word.
-
- ø 29.3 Ethernet Write-Data Structure
-
- When you first open the .ENET driver, it allocates a 768-byte buffer that it
- uses for transmitting data packets. This buffer is large enough to hold the
- largest EtherTalk packet, which is 617 bytes in size. If you want to transmit
- data packets larger than 768 bytes, call the ESetGeneral function. The .ENET
- driver then allocates a large enough data buffer to send packets up to 1514
- bytes in size.
-
- Listing 29-8 defines an Ethernet write-data structure and then calls the EWrite
- function to send a data packet over Ethernet.
-
- Listing 29-8. Sending a Data Packet Over Ethernet (TO BE PROVIDED)
- _______________________________________________________________________________
-
- æKY Using…the…Default…Ethernet…Protocol…Handler…to…Read…Data
- æC »Using the Default Ethernet Protocol Handler to Read Data AppleTalk Manager
- _______________________________________________________________________________
-
- When the EtherTalk Nubus card or other Ethernet hardware receives a data packet,
- it generates an interrupt to the CPU. The interrupt handler in ROM determines
- the source of the interrupt and calls the .ENET driver. The .ENET driver reads
- the packet header to determine the protocol type of the data packet and checks
- to see if any client has specified that protocol type in a call to the EAttachPH
- function. If so, the client either specified a NIL pointer to a protocol
- handler, or the client provided its own protocol handler. If the client
- specified a NIL pointer, the .ENET driver uses its default protocol handler to
- read the data. If no one has specified that protocol type in a call to the
- EAttachPH function, the .ENET driver discards the data. The EAttachPH function
- is described in
- “Attaching and Detaching an Ethernet Protocol Handler” later in this chapter.
-
- The default protocol handler checks for an ERead function pending execution and
- places the entire packet—including the packet header—into the buffer specified
- by that function. The function returns the number of bytes actually read. If the
- packet is larger than the data buffer, the ERead function places as much of the
- packet as will fit into the buffer and returns the buf2SmallErr result code.
-
- Call the ERead function asynchronously to await the next data packet. When the
- .ENET driver receives the data packet, it completes execution of the ERead
- function and calls your completion routine. Your completion routine should call
- the ERead function again so that there is always an ERead function pending
- execution. If the .ENET driver receives a data packet with a protocol type for
- which you specified the default protocol handler, but there is no ERead function
- pending, the .ENET driver discards the packet.
-
- You can have several asynchronous calls to the ERead function pending execution
- simultaneously, as long as you use a different parameter block for each call.
-
- Listing 29-9 defines a completion routine.
-
- Listing 29-9. Using the Default Ethernet Protocol Handler to Read Data (TO BE
- PROVIDED)
-
- _______________________________________________________________________________
-
- æKY Using…Your…Own…Ethernet…Protocol…Handler…to…Read…Data
- æC »Using Your Own Ethernet Protocol Handler to Read Data AppleTalk Manager
- _______________________________________________________________________________
-
- If a client of the .ENET driver has used the EAttachPH function to provide a
- pointer to its own protocol handler, the .ENET driver calls that protocol
- handler, which must in turn call the .ENET driver’s ReadPacket and ReadRest
- routines to read the data. Your protocol handler calls the .ENET driver’s
- ReadPacket and ReadRest routines in essentially the same way as you call the
- .MPP drivers ReadPacket and ReadRest routines (see the AppleTalk Manager chapter
- of Volume II). The following sections describe the .ENET driver’s call to a
- custom protocol handler and the ReadPacket and ReadRest routines.
-
- Note: Because an Ethernet protocol handler must read from and write to the
- CPU’s registers, you cannot write a protocol handler in Pascal.
- _______________________________________________________________________________
-
- æKY How…the….ENET…Driver…Calls…Your…Protocol…Handler
- æC »How the .ENET Driver Calls Your Protocol Handler AppleTalk Manager
- _______________________________________________________________________________
-
- You can provide an Ethernet protocol handler for a particular protocol type and
- use the EAttachPH function to attach it to the .ENET driver. When the driver
- receives an Ethernet packet, it reads the packet header into an internal buffer,
- reads the protocol type, and calls the protocol handler for that protocol type.
- The CPU is in interrupt mode and the registers are used as follows:
-
- Registers on call to Ethernet protocol handler
-
- A0
- Reserved for internal use by the .ENET driver; you must preserve this register
- until after the ReadRest routine has completed execution
-
- A1
- Reserved for internal use by the .ENET driver; you must preserve this register
- until after the ReadRest routine has completed execution
-
- A2 Free for your use
-
- A3
- Pointer to first byte past data-link header bytes (the first byte after the
- 2-byte protocol-type field)
-
- A4
- Pointer to the ReadPacket routine; the ReadRest routine starts 2 bytes after the
- start of the ReadPacket routine
-
- A5
- Free for your use until after the ReadRest routine has completed execution
-
- D0 Free for your use
-
- D1
- Number of bytes in the Ethernet packet left to be read (that is, the number of
- bytes following the Ethernet header)
-
- D2 Free for your use
-
- D3 Free for your use
-
- If your protocol handler processes more than one protocol type, you can read the
- protocol-type field in the data-link header to determine the protocol type of
- the packet. The protocol-type field starts 2 bytes before the address pointed to
- by the A3 register.
-
- Note: The source address starts 8 bytes before the address pointed to by the A3
- register and the destination address starts 14 bytes before the address pointed
- to by the A3 register.
-
- If you know that the packet contains pad bytes and you know the actual size of
- the data, you can reduce the number in the D1 register by the number of pad
- bytes so that the .ENET driver can keep accurate track of the number of bytes
- remaining to be read. In all other circumstances, you should not change the
- value in the D1 register.
-
- After you have called the ReadRest routine, you can use registers A0 through A3
- and D0 through D3 for your own use, and must preserve all other registers. You
- cannot depend on having access to your application global variables.
-
- _______________________________________________________________________________
-
- æKY How…Your…Protocol…Handler…Calls…the….ENET…Driver
- æC »How Your Protocol Handler Calls the .ENET Driver AppleTalk Manager
- _______________________________________________________________________________
-
- Your protocol handler must call the .ENET driver routines ReadPacket and
- ReadRest to read the incoming data packet. You may call the ReadPacket routine
- as many times as you like to read the data piece-by-piece into one or more data
- buffers, but you must always use the ReadRest routine to read the final piece of
- the data packet. The ReadRest routine restores the machine state (the stack
- pointers, status register, and so forth) and checks for error conditions.
- Before you call the ReadPacket routine, you must allocate memory for a data
- buffer and place a pointer to the buffer in the A3 register. You place the
- number of bytes you want to read in the D3 register. You must not request more
- bytes than remain in the data packet.
-
- To call the ReadPacket routine, execute a JSR instruction to the address in the
- A4 register. The ReadPacket routine uses the registers as follows:
-
- Registers on entry to the ReadPacket routine
-
- A3 Pointer to a buffer to hold the data you want to read
- D3 Number of bytes to read; must be nonzero
-
- Registers on exit from the ReadPacket routine
-
- A0 Unchanged
- A1 Unchanged
- A2 Unchanged
- A3 Pointer to next byte to read (first byte after the last byte read)
- D0 Changed
- D1 Number of bytes left to be read
- D2 Unchanged
- D3 Equals 0 if requested number of bytes were read, nonzero if error
-
- The ReadPacket routine indicates an error by clearing to 0 the zero (z) flag in
- the status register. If the ReadPacket routine returns an error, you must
- terminate execution of your protocol handler with an RTS instruction without
- calling ReadPacket again or calling ReadRest at all.
-
- Call the ReadRest routine to read the last portion of the data packet, or call
- it after you have read all the data with ReadPacket routines and before you do
- any other processing or terminate execution. You must provide in the A3 register
- a pointer to a data buffer and must indicate in the D3 register the size of the
- data buffer. If you have already read all of the data with calls to the
- ReadPacket routine, you can specify a 0-size buffer.
-
- † Warning: If you do not call the ReadRest routine after your last call to the
- ReadPacket routine, the system will crash. Ê
-
- To call the ReadRest routine, execute a JSR instruction to an address 2 bytes
- past the address in the A4 register. The ReadRest routine uses the registers as
- follows:
-
- Registers on entry to the ReadRest routine
-
- A3 Pointer to a buffer to hold the data you want to read
- D3 Size of the buffer (word length); may be 0
-
- Registers on exit from the ReadRest routine
-
- A0 Unchanged
- A1 Unchanged
- A2 Unchanged
- A3 Pointer to first byte after the last byte read
- D0 Changed
- D1 Changed
- D2 Unchanged
- D3 Equals 0 if requested number of bytes were read; less than 0 if there was
- more data left than would fit in buffer (extra data equals –D3 bytes); greater
- than 0 if there was less data left than the size of the buffer (extra buffer
- space equals D3 bytes)
-
- If the buffer you provide is not large enough to hold the remaining bytes in the
- packet, the ReadRest routine returns an error. The ReadRest routine indicates an
- error by clearing to 0 the zero (z) flag in the status register.
-
- You must terminate execution of your protocol handler with an RTS instruction
- whether or not the ReadRest routine returns an error.
-
- _______________________________________________________________________________
-
- æKY ENET…Driver…Routines
- æC »ENET Driver Routines AppleTalk Manager
- _______________________________________________________________________________
-
- An application that uses AppleTalk Manager routines for network communications
- can talk to whatever network the user has selected through the Network control
- panel. However, you can choose to write an application that talks only to
- Ethernet; in this case, your application has to address the Ethernet driver
- directly. This section describes the functions that you can use to control the
- .ENET driver, the Ethernet driver provided with system software version 7.0.
- Each.ENET driver function is of the form
-
- FUNCTION Efunc (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- where the thePBptr parameter is a pointer to the .ENET parameter block and the
- async parameter is a Boolean that specifies whether the function is to be
- executed synchronously or asynchronously. Set the async parameter to TRUE to
- execute the function asynchronously.
-
- The .ENET parameter block is defined as follows:
-
- EParamBlock = PACKED RECORD
- qLink: QElemPtr; {next queue entry}
- qType: INTEGER; {queue type}
- ioTrap: INTEGER; {routine trap}
- ioCmdAddr: Ptr; {routine address}
- ioCompletion: ProcPtr; {completion routine}
- ioResult: OsErr; {result code}
- ioNamePtr: StringPtr; {driver name}
- ioVRefNum: INTEGER; {volume reference number}
- ioCRefNum: INTEGER; {driver reference number}
- csCode: INTEGER; {primary command code}
-
- CASE INTEGER OF
- EWrite,
- EAttachPH,
- EDetachPH,
- ERead,
- ERdCancel,
- EGetInfo,
- ESetGeneral:
- (
- EProtType: INTEGER; {Ethernet protocol type}
- EPointer: Ptr; {pointer; use depends on function}
- EBuffSize INTEGER {buffer size}
- EDataSize INTEGER {number of bytes read}
- );
-
- EAddMulti,
- EDelMulti:
- (
- EMultiAddr: ?????; {Multicast address}
- );
- END;
-
- The qLink, qType, ioTrap, ioCmdAddr, ioNamePtr, and ioVRefNum fields are
- standard parameters provided by the Pascal or C interface; your application
- should not have to set or read these parameters. The ioResult parameter returns
- the result of the function; in the case that you call the function
- asynchronously, the function sets this field to 1 as soon as it begins
- execution, and changes the field to the actual result code when it completes
- execution. The ioCompletion parameter is a pointer to a completion routine that
- you can provide; the Device Manager calls your completion routine when it
- completes execution of the function. If you are not providing a completion
- routine, specify NIL for this field. The ioCRefNum and csCode fields specify the
- driver and the command to be executed; the MPW Pascal interface fills in these
- fields for you. The Control function is discussed in the Device Manager chapter
- of Volume II.
-
- The remaining parameters are used only for specific functions; all of these
- parameters are described in the following sections.
-
- For a general discussion of the use of the Ethernet driver, see “The .ENET
- Driver” earlier in this chapter.
-
- _______________________________________________________________________________
-
- æKY Attaching…and…Detaching…an…Ethernet…Protocol…Handler
- æC »Attaching and Detaching an Ethernet Protocol Handler AppleTalk Manager
- _______________________________________________________________________________
-
- The functions in this section allow you to attach a protocol handler to the
- .ENET driver, to specify which protocol handler the .ENET driver is to use for
- each protocol type, and to detach a protocol handler that you previously
- attached. The section “Using Your Own Ethernet Protocol Handler to Read Data”
- earlier in this chapter, describes how to write and use Ethernet protocol
- handlers.
-
- FUNCTION EAttachPH (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always EAttachPH
- Æ 28 EProtType word Ethernet protocol type
- Æ 30 EPointer pointer pointer to protocol handler
-
- The EAttachPH function serves two purposes: You can use it to attach to the
- .ENET driver your own protocol handler for a specific protocol type; or you can
- use it to specify that the .ENET driver should use the default protocol handler
- for a particular protocol type. If you attach your own protocol handler, the
- .ENET driver calls that protocol handler each time it receives a packet with the
- protocol type you specified. If you specify that the .ENET driver should use the
- default protocol handler, then you can use the ERead command to read packets
- with that protocol type.
-
- The ioResult parameter returns the result of the function; if you call the
- function asynchronously, the function sets this field to 1 as soon as it begins
- execution, and changes the field to the actual result code when it completes
- execution. The csCode parameter is a routine selector that is set automatically
- for you by the MPW interface; it is always equal to EAttachPH for this function.
- You specify the protocol type in the EProtType parameter and provide a pointer
- to the protocol handler in the EPointer parameter. If you specify NIL for the
- EPointer parameter, then the .ENET driver uses the default protocol handler for
- that protocol type. Specify 0 for the EProtType parameter to attach a protocol
- handler for the IEEE 802.3 protocol, which uses protocol types 0 through $5DC.
-
- Note: In addition to using the EAttachPH function to install a protocol handler
- for an Ethernet protocol type, you can use the L802Attach function to install a
- protocol handler for an 802.2 protocol type. In the case of an 802.2 protocol
- packet, the .ENET driver passes the packet to the LAP Manager 802.2 protocol
- handler. If the packet has the protocol type you specified with the L802Attach
- function, the 802.2 protocol handler passes the packet on to your protocol
- handler. See “The LAP Manager 802.2 Protocol” earlier in this chapter, for more
- information about IEEE 802.2 protocols.
-
- Result codes
- noErr 0 no error
- LAPProtErr –94 protocol handler is already attached or node’s protocol
- table is full
-
- FUNCTION EDetachPH (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always EDetachPH
- Æ 28 EProtType word Ethernet protocol type
-
- The EDetachPH function detaches a protocol handler from the .ENET driver. Once
- you have removed a protocol type from the node’s protocol table with this
- command, the .ENET driver no longer delivers packets with that protocol type.
- You specify the protocol type in the EProtType parameter.
-
- The ioResult parameter returns the result of the function; if you call the
- function asynchronously, the function sets this field to 1 as soon as it begins
- execution, and changes the field to the actual result code when it completes
- execution. The csCode parameter is a routine selector that is set automatically
- for you by the MPW interface; it is always equal to EAttachPH for this function.
-
- Result codes
- noErr 0 no error
- LAPProtErr –94 no protocol handler attached
- _______________________________________________________________________________
-
- æKY Writing…and…Reading…Packets…Using…the…Default…Protocol…Handler
- æC »Writing and Reading Packets Using the Default Protocol Handler AppleTalk Manager
- _______________________________________________________________________________
-
- FUNCTION EWrite (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always EWrite
- Æ 30 EPointer pointer pointer to write-data structure
-
- The EWrite function uses the .ENET driver to send a data packet over Ethernet.
- You must first prepare a write-data structure, which specifies the destination
- address and the protocol type and contains the data that you want to send. You
- place a pointer to the write-data structure in the EPointer parameter. If you
- want to send a packet larger than 768 bytes, you must first call the ESetGeneral
- command to put the .ENET driver in general transmission mode. If the size of the
- packet you provide is less than 60 bytes, the driver adds pad bytes to the
- packet. Write-data structures are described in “Using a Write-Data Structure to
- Transmit Ethernet Data” earlier in this chapter.
-
- The ioResult parameter returns the result of the function; if you call the
- function asynchronously, the function sets this field to 1 as soon as it begins
- execution, and changes the field to the actual result code when it completes
- execution. The csCode parameter is a routine selector that is set automatically
- for you by the MPW interface; it is always equal to EWrite for this function.
-
- Result codes
- noErr 0 no error
- elenErr packet too large or first write-data-structure entry did
- not contain the full 14-byte header
- excessCollsns –95 hardware error
-
- FUNCTION ERead (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always ERead
- Æ 28 EProtType word Ethernet protocol type
- Æ 30 EPointer pointer pointer to data buffer
- Æ 34 EBuffSize word size of data buffer
- ¨ 36 EDataSize word number of bytes read
-
- The ERead function uses the default protocol handler to read a data packet and
- place it in a data buffer. You can use the ERead function to read packets of a
- particular protocol type only after you have used the EAttachPH function to
- specify a NIL pointer to the protocol handler for that protocol type.
-
- The ioResult parameter returns the result of the function; if you call the
- function asynchronously, the function sets this field to 1 as soon as it begins
- execution, and changes the field to the actual result code when it completes
- execution. The csCode parameter is the routine selector, automatically set by
- the MPW interface. It is always ERead for this function. The ccbRefNum parameter
- is the connection control block reference number that was returned by the
- dspInit command.
-
- The EProtType parameter specifies the protocol type of the packet you want to
- read. The EPointer parameter is a pointer to the data buffer into which you want
- to read data, and the EBuffSize parameter indicates the size of the data buffer.
- If you are expecting EtherTalk data packets, the buffer should be at least 617
- bytes in size; if you are expecting general Ethernet data packets, the buffer
- should be at least 1514 bytes in size.
-
- The ERead function places the entire packet—including the packet header—into
- your buffer. The function returns in the EDataSize parameter the number of bytes
- actually read. If the packet is larger than the data buffer, the ERead function
- places as much of the packet as will fit into the buffer and returns the
- buf2SmallErr result code.
-
- Call the ERead function asynchronously to await the next data packet. When the
- .ENET driver receives the data packet, it completes execution of the ERead
- function and calls your completion routine. If the .ENET driver receives a data
- packet with a protocol type for which you specified the default protocol
- handler, but there is no ERead command pending, the driver discards the data
- packet.
-
- You can have several asynchronous calls to the ERead function pending execution
- simultaneously, as long as you use a different parameter block for each call.
-
- Result codes
- noErr 0 no error
- LAPProtErr –94 protocol not attached or protocol handler pointer was not 0
- buf2SmallErr –3101 packet too large for buffer; partial data returned
- reqAborted –1105 ERdCancel function called for this ERead
-
- FUNCTION ERdCancel (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always ERdCancel
- Æ 30 EPointer pointer pointer to ERead parameter block
-
- The ERdCancel function cancels execution of a specific call to the ERead
- function. You must have called the ERead function asynchronously to use the
- ERdCancel function. You specify in the EPointer parameter a pointer to the
- parameter block that you used when you called the ERead function.
- The ioResult parameter returns the result of the function; if you call the
- function asynchronously, the function sets this field to 1 as soon as it begins
- execution, and changes the field to the actual result code when it completes
- execution. The csCode parameter is the routine selector, automatically set by
- the MPW interface. It is always ERdCancel for this function. The ccbRefNum
- parameter is the connection control block reference number that was returned by
- the dspInit command.
-
- Result codes
- noErr 0 no error
- CBNotFound –1102 ERead not active
-
- FUNCTION EGetInfo (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always EGetInfo
- Æ 30 EPointer pointer pointer to buffer
- Æ 34 EBuffSize word size of buffer
-
- The EGetInfo function returns information about the .ENET driver. Before calling
- this function, you must allocate a data buffer of at least 18 bytes. Put a
- pointer to the buffer in the EPointer parameter and the size of the buffer in
- the EBuffSize parameter.
-
- The EGetInfo function places the following information in the data buffer:
-
- Bytes Information
-
- 1–6 Ethernet address of the node on which the driver is installed
- 7–10 Number of times the receive buffer has overflowed
- 11–14 Number of data transmission operations that have timed out
- 15–18 Number of packets received that contain an incorrect address
-
- The ioResult parameter returns the result of the function; if you call the
- function asynchronously, the function sets this field to 1 as soon as it begins
- execution, and changes the field to the actual result code when it completes
- execution. The csCode parameter is the routine selector, automatically set by
- the MPW interface. It is always EGetInfo for this function. The ccbRefNum
- parameter is the connection control block reference number that was returned by
- the dspInit command.
-
- Result code
- noErr 0 no error
-
- FUNCTION ESetGeneral (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always ESetGeneral
-
- The ESetGeneral function switches the .ENET driver from limited-transmission
- mode to general-transmission mode. In limited-transmission mode, the .ENET
- driver allocates a write-data buffer of 768 bytes. This buffer size is more than
- sufficient to hold an EtherTalk data packet, which can be no larger than 617
- bytes. In general-transmission mode, the .ENET driver can transmit an Ethernet
- data packet of up to 1514 bytes.
-
- The ioResult parameter returns the result of the function; if you call the
- function asynchronously, the function sets this field to 1 as soon as it begins
- execution, and changes the field to the actual result code when it completes
- execution. The csCode parameter is the routine selector, automatically set by
- the MPW interface. It is always ESetGeneral for this function. The ccbRefNum
- parameter is the connection control block reference number that was returned by
- the dspInit command.
-
- There is no command to switch the .ENET driver from general-transmission mode to
- limited-transmission mode. To switch back to limited-transmission mode, you have
- to reset the driver by restarting the computer.
-
- Result codes
- noErr 0 no error
- _______________________________________________________________________________
-
- æKY Adding…and…Removing…Ethernet…Multicast…Addresses
- æC »Adding and Removing Ethernet Multicast Addresses AppleTalk Manager
- _______________________________________________________________________________
-
- FUNCTION EAddMulti (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always EAddMulti
- Æ 28 EMultiAddr 6 bytes multicast address
-
- The EAddMulti function adds a multicast address to the node on which the .ENET
- driver is running. A multicast address is an Ethernet address for which the node
- accepts packets just as it does to its permanently assigned Ethernet hardware
- address. In a muticast address, the low-order bit of the high-order byte is set
- to 1. Each node can have any number of multicast addresses, and any number of
- nodes can have the same multicast address. The purpose of a multicast address is
- to allow a group of Ethernet nodes to receive the same transmission
- simultaneously, in a fashion similar to the AppleTalk broadcast service.
-
- You must provide (in the EMultiAddr parameter) the multicast address that you
- want to use. Each time a client of the .ENET driver calls the EAddMulti function
- for a particular multicast address, the driver increments a counter for that
- multicast address. Each time a client of the .ENET driver calls the EDelMulti
- function, the driver decrements the counter for that address. As long as the
- count for a multicast address is equal to or greater than 1, the .ENET driver
- accepts packets directed to that multicast address. If any client of the .ENET
- driver in the node has called the EAddMulti function for a particular multicast
- address, therefore, the driver receives packets delivered to that address.
-
- The ioResult parameter returns the result of the function; if you call the
- function asynchronously, the function sets this field to 1 as soon as it begins
- execution, and changes the field to the actual result code when it completes
- execution. The csCode parameter is the routine selector, automatically set by
- the MPW interface. It is always EAddMulti for this function. The ccbRefNum
- parameter is the connection control block reference number that was returned by
- the dspInit command.
-
- Result codes
- noErr 0 no error
- eMultiErr invalid address or table is full
-
- FUNCTION EDelMulti (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always EDelMulti
- Æ 28 EMultiAddr 6 bytes multicast address
-
- The EDelMulti function decrements the counter kept by the .ENET driver for a
- particular multicast address. Each time a client of the .ENET driver calls the
- EAddMulti function, the driver increments a counter for the multicast address
- specified by the EMultiAddr parameter. Each time a client of the .ENET driver
- calls the EDelMulti function, the driver decrements the counter for the address
- specified by the EMultiAddr parameter. As long as the count for a multicast
- address is equal to or greater than 1, the .ENET driver accepts packets directed
- to that multicast address. When the count for an address equals 0, the driver
- removes that address from the list of multicast addresses that it accepts.
-
- Note: Because more than one client of the .ENET driver might be using a
- particular multicast address, you should call the EDelMulti function only once
- for each time you called the EAddMulti function.
-
- The ioResult parameter returns the result of the function; if you call the
- function asynchronously, the function sets this field to 1 as soon as it begins
- execution, and changes the field to the actual result code when it completes
- execution. The csCode parameter is the routine selector, automatically set by
- the MPW interface. It is always EDelMulti for this function. The ccbRefNum
- parameter is the connection control block reference number that was returned by
- the dspInit command.
-
- Result codes
- noErr 0 no error
- eMultiErr address not found
- _______________________________________________________________________________
-
- æKY Summary…of…the…AppleTalk…Manager
- æC »SUMMARY OF THE APPLETALK MANAGER AppleTalk Manager
- _______________________________________________________________________________
-
- The following cards summarize the constants, data types, and routines for the
- AppleTalk Manager.
- _______________________________________________________________________________
-
- æKY AppleTalk…Constants
- æC »Constants AppleTalk Manager
- _______________________________________________________________________________
-
- CONST
- {csCodes for new .XPP driver routines}
- xCall = 246;
-
- {xppSubCodes}
- getLocalZones = 5;
- getZoneList = 6;
- getMyZone = 7;
-
-
- {driver control csCodes}
- dspInit = 255; {create a new connection end}
- dspRemove = 254; {remove a connection end}
- dspOpen = 253; {open a connection}
- dspClose = 252; {close a connection}
- dspCLInit = 251; {create a connection listener}
- dspCLRemove = 250; {remove a connection listener}
- dspCLListen = 249; {post a listener request}
- dspCLDeny = 248; {deny an open connection request}
- dspStatus = 247; {get status of connection end}
- dspRead = 246; {read data from the connection}
- dspWrite = 245; {write data on the connection}
- dspAttention = 244; {send an attention message}
- dspOptions = 243; {set connection end options}
- dspReset = 242; {forward reset the connection}
- dspNewCID = 241; {generate a cid for a connection end}
-
- {connection opening modes}
- ocRequest = 1; {request a connection with remote}
- ocPassive = 2; {wait for a connection request from remote}
- ocAccept = 3; {accept request as delivered by listener}
- ocEstablish = 4; {consider connection to be open}
-
- {connection end states}
- sListening = 1; {for connection listeners}
- sPassive = 2; {waiting for a connection request from remote}
- sOpening = 3; {requesting a connection with remote}
- sOpen = 4; {connection is open}
- sClosing = 5; {connection is being torn down}
- sClosed = 6; {connection end state is closed}
-
- {client event flags}
- eClosed = $80; {received connection closed advice}
- eTearDown = $40; {closed due to broken connection}
- eAttention = $20; {received attention message}
- eFwdReset = $10; {received forward reset advice}
-
- {miscellaneous constants}
- attnBufSize = 570; {size of client attention buffer}
- minDSPQueueSize = 100; {Minimum size of receive or send Queue}
- _______________________________________________________________________________
-
- æKY AppleTalk…Data…Types
- æC »Data Types AppleTalk Manager
- _______________________________________________________________________________
-
- TYPE ATQentry = RECORD
- qLink: ATQentryPtr; {next queue entry}
- qType: INTEGER; {unused}
- CallAddr: ProcPtr {pointer to your routine}
- END;
-
- ATQentryptr = ^ATQentry;
-
- TPCCB = ^TRCCB;
-
- TRCCB = PACKED RECORD
- ccbLink: TPCCB; {link to next CCB}
- refNum: INTEGER; {user reference number}
- state: INTEGER; {state of the connection end}
- userFlags: Byte; {user flags for connection}
- localSocket: Byte; {local socket number}
- remoteAddress: AddrBlock; {remote end internet address}
- attnCode: INTEGER; {attention code received}
- attnSize: INTEGER; {size of attention data}
- attnPtr: Ptr; {pointer to attention data}
- reserved: PACKED ARRAY [1..220] OF Byte {reserved for use by ADSP}
- END;
-
- AddrBlock = PACKED RECORD
- aNet: INTEGER; {network number}
- aNode: Byte; {node ID}
- aSocket: Byte {socket number}
- END;
-
- DSPParamBlock = PACKED RECORD
- qLink: QElemPtr; {next queue entry}
- qType: INTEGER; {queue type}
- ioTrap: INTEGER; {routine trap}
- ioCmdAddr: Ptr; {routine address}
- ioCompletion: ProcPtr; {completion routine}
- ioResult: OSErr; {result code}
- ioNamePtr: StringPtr; {used only for Open routine}
- ioVRefNum: INTEGER; {volume reference number}
- ioCRefNum: INTEGER; {driver reference number}
- csCode: INTEGER; {primary command code}
- qStatus: LONGINT; {reserved for ADSP}
- ccbRefNum: INTEGER; {CCB reference number}
- CASE INTEGER OF
- dspInit,
- dspCLInit:
- (
- ccbPtr: TPCCB; {pointer to CCB}
- userRoutine: ProcPtr; {pointer to user routine}
- sendQSize: INTEGER; {size of send queue}
- sendQueue: Ptr; {pointer to send queue}
- recvQSize: INTEGER; {size of receive queue}
- recvQueue: Ptr; {pointer to receive queue}
- attnPtr: Ptr; {pointer to attention-message buffer}
- localSocket: Byte; {local socket number}
- );
-
- dspOpen,
- dspCLListen,
- dspCLDeny:
- (
- localCID: INTEGER; {local connection ID}
- remoteCID: INTEGER; {remote connection ID}
- remoteAddress: AddrBlock; {remote internet address}
- filterAddress: AddrBlock; {address filter}
- sendSeq: LONGINT; {send sequence number}
- sendWindow: INTEGER; {size of remote buffer}
- recvSeq: LONGINT; {receive sequence number}
- attnSendSeq: LONGINT; {attention send seq number}
- attnRecvSeq: LONGINT; {attention receive seq num}
- ocMode: Byte; {connection opening mode}
- ocInterval: Byte; {interval bet open requests}
- ocMaximum: Byte; {retries of open conn req}
- );
-
- dspClose,
- dspRemove:
- (
- abort: Byte; {abort send requests}
- );
-
- dspStatus:
- (
- statusCCB: TPCCB; {pointer to CCB}
- sendQPending: INTEGER; {bytes waiting in send queue}
- sendQFree: INTEGER; {available send-queue buffer}
- recvQPending: INTEGER; {bytes in receive queue}
- recvQFree: INTEGER; {avail receive-queue buffer}
- )
-
- dspRead,
- dspWrite:
- (
- reqCount: INTEGER; {requested number of bytes}
- actCount: INTEGER; {actual number of bytes}
- dataPtr: Ptr; {pointer to data buffer}
- eom: Byte; {1 if end of message}
- flush: Byte; {1 to send data now}
- )
-
- dspAttention:
- (
- attnCode: INTEGER; {client attention code}
- attnSize: INTEGER; {size of attention data}
- attnData: Ptr; {pointer to attention data}
- attnInterval: Byte; {reserved}
- )
-
- dspOptions:
- (
- sendBlocking: INTEGER; {send-blocking threshold}
- sendTimer: Byte; {reserved}
- rtmtTimer: Byte; {reserved}
- badSeqMax: Byte; {retransmit advice threshold}
- useCheckSum: Byte; {DDP checksum for packets}
- )
-
- dspNewCID:
- (
- newCID: INTEGER; {new connection ID}
- )
- END;
-
- xCallParam = PACKED RECORD
- qLink: QElemPtr; {next queue entry}
- qType: INTEGER; {queue type}
- ioTrap: INTEGER; {routine trap}
- ioCmdAddr: Ptr; {routine address}
- ioCompletion: ProcPtr; {completion routine}
- ioResult: OsErr; {result code}
- ioNamePtr: StringPtr; {used only for Open routine}
- ioVRefNum: INTEGER; {volume reference number}
- ioRefNum: INTEGER; {driver reference number}
- csCode: INTEGER; {primary command code}
- xppSubCode: INTEGER; {secondary command code}
- xppTimeOut: Byte; {timeout period for .XPP}
- xppRetry: Byte; {retry count}
- filler: INTEGER; {reserved}
- zipBuffPtr: Ptr; {returned zone names}
- zipNumZones: INTEGER; {number of zones returned}
- zipLastFlag: Byte; {nonzero when all zone names have been returned}
- filler: Byte; {reserved}
- zipInfoField: packed array[1..70] of Byte
- {reserved for use by .XPP}
- END;
-
- XCallParamPtr = ^XCallParam;
- EParamBlock = PACKED RECORD
- qLink: QElemPtr; {next queue entry}
- qType: INTEGER; {queue type}
- ioTrap: INTEGER; {routine trap}
- ioCmdAddr: Ptr; {routine address}
- ioCompletion: ProcPtr; {completion routine}
- ioResult: OsErr; {result code}
- ioNamePtr: StringPtr; {driver name}
- ioVRefNum: INTEGER; {volume reference number}
- ioCRefNum: INTEGER; {driver reference number}
- csCode: INTEGER; {primary command code}
-
- CASE INTEGER OF
- EWrite,
- EAttachPH,
- EDetachPH,
- ERead,
- ERdCancel,
- EGetInfo,
- ESetGeneral:
-
- (
- EProtType: INTEGER; {Ethernet protocol type}
- EPointer: Ptr; {pointer; use depends on }
- { function}
- EBuffSize INTEGER {buffer size}
- EDataSize INTEGER {number of bytes read}
- );
-
- EAddMulti,
- EDelMulti:
-
- (
- EMultiAddr: ?????; {Multicast address}
- );
- END;
- _______________________________________________________________________________
-
- æKY AppleTalk…Routines
- æC »Routines AppleTalk Manager
- _______________________________________________________________________________
-
- Getting Information About the .MPP Driver
-
- FUNCTION PGetAppleTalkInfo (thePBptr: MPPPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always PGetAppleTalkInfo
- Æ 28 version word version of function
- ¨ 30 varsPtr pointer pointer to MPP globals
- ¨ 34 dcePtr pointer pointer to DCE for .MPP
- ¨ 38 portID word port number
- ¨ 40 configuration long configuration flags
- ¨ 44 selfSend word nonzero if self-send is enabled
- ¨ 46 netLo word low value of the network range
- ¨ 48 netHi word high value of the network range
- ¨ 50 ourAddr long local 24-bit AppleTalk address
- ¨ 54 routerAddr long 24-bit address of router
- ¨ 58 numOfPHs word max number of protocol handlers
- ¨ 60 numOfSkts word max number of static sockets
- ¨ 62 numNBPEs word max concurrent NBP requests
- ¨ 64 ntQueue pointer pointer to registered name queue
- ´ 68 laLength word length in bytes of data link address
- (extended networks only)
- Æ 70 linkAddr pointer pointer to data link address buffer
- (extended networks only)
- Æ 74 zoneName pointer pointer to zone name buffer
-
- Adding and Removing AppleTalk Transition Queue Entries
-
- PROCEDURE LAPAddATQ (entryPtr: pointer);
- PROCEDURE LAPRmvATQ (entryPtr: pointer);
- PROCEDURE LAPGetATQ (VAR eqPtr: pointer);
-
- Sending Messages to the AppleTalk Transition Queue
-
- FUNCTION PATalkClosePrep (thePBptr: MPPPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- Æ 26 csCode word always PATalkClosePrep
- Æ appName pointer buffer for name of application that
- denies request
-
- FUNCTION PCancelATClosePrep (thePBptr: MPPPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- Æ 26 csCode word always PCancelATClosePrep
-
- Attaching and Detaching 802.2 Protocol Handlers
-
- FUNCTION L802Attach (Eref: word; handlerPtr: procptr;
- ProtType: pointer) : OSErr;
- FUNCTION L802Detach (Eref: word; ProtType: pointer) : OSErr;
-
- Canceling Asynchronous Calls to the ATPKillAllGetReq Function
-
- FUNCTION ATPKillAllGetReq (thePBptr: ATPPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- Æ 26 csCode word always ATPKillAllGetReq
- Æ 28 atpSocket byte socket for which to cancel all calls
- to ATPGetRequest
-
- Using the .XPP Driver to Obtain Zone Information
-
- FUNCTION GetMyZone (thePBptr:XCallParamPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word routine selector; always xCall
- Æ 28 xppSubCode word routine selector; getMyZone
- Æ 30 xppTimeOut byte retry interval in seconds
- Æ 31 xppRetry byte retry count
- Æ 34 zipBuffPtr long pointer to data buffer
- Æ 42 zipInfoField 70 bytes for use by ZIP; first word set to 0
-
- FUNCTION GetLocalZones (thePBptr:XCallParamPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word routine selector; always xCall
- Æ 28 xppSubCode word routine selector; getLocalZones
- Æ 30 xppTimeOut byte retry interval in seconds
- Æ 31 xppRetry byte retry count
- Æ 34 zipBuffPtr pointer pointer to data buffer
- ¨ 38 zipNumZones word number of names returned
- ¨ 40 zipLastFlag byte nonzero if no more names
- Æ 42 zipInfoField 70 bytes for use by ZIP; first word set to 0
-
- FUNCTION GetZoneList (thePBptr:XCallParamPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word routine selector; always xCall
- Æ 28 xppSubCode word routine selector; getZoneList
- Æ 30 xppTimeOut byte retry interval in seconds
- Æ 31 xppRetry byte retry count
- Æ 34 zipBuffPtr pointer pointer to data buffer
- ¨ 38 zipNumZones word number of names returned
- ¨ 40 zipLastFlag byte nonzero if no more names
- Æ 42 zipInfoField 70 bytes for use by ZIP; first word set to 0
-
- Attaching and Detaching an Ethernet Protocol Handler
-
- FUNCTION EAttachPH (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always EAttachPH
- Æ 28 EProtType word Ethernet protocol type
- Æ 30 EPointer pointer pointer to protocol handler
-
- FUNCTION EDetachPH (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always EDetachPH
- Æ 28 EProtType word Ethernet protocol type
-
- Writing and Reading Ethernet Packets Using the Default Protocol Handler
-
- FUNCTION EWrite (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always EWrite
- Æ 30 EPointer pointer pointer to write-data structure
-
- FUNCTION ERead (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always ERead
- Æ 28 EProtType word Ethernet protocol type
- Æ 30 EPointer pointer pointer to data buffer
- Æ 34 EBuffSize word size of data buffer
- ¨ 36 EDataSize word number of bytes read
-
- FUNCTION ERdCancel (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always ERdCancel
- Æ 30 EPointer pointer pointer to ERead parameter block
-
- FUNCTION EGetInfo (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always EGetInfo
- Æ 30 EPointer pointer pointer to buffer
- Æ 34 EBuffSize word size of buffer
-
- FUNCTION ESetGeneral (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always ESetGeneral
-
- Adding and Removing Ethernet Multicast Addresses
-
- FUNCTION EAddMulti (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always EAddMulti
- Æ 28 EMultiAddr 6 bytes multicast address
-
- FUNCTION EDelMulti (thePBptr: EPBPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- ¨ 16 ioResult word result code
- Æ 26 csCode word always EDelMulti
- Æ 28 EMultiAddr 6 bytes multicast address
- _______________________________________________________________________________
-
- æKY AppleTalk…Result…codes
- æC »Result codes AppleTalk Manager
- _______________________________________________________________________________
-
- eMultiErr invalid address or table is full
- elenErr packet too large or first write-data-structure entry
- did not contain the full 14-byte header
- noErr 0 no error
- closeErr –24 permission to close .MPP driver was denied
- ddpSktErr –91 error opening socket
- noBridgeErr –93 no router is available
- LAPProtErr –94 protocol handler is already attached or node’s protocol
-
- table is full
- LAPProtErr –94 no protocol handler attached
- LAPProtErr –94 protocol not attached or protocol handler pointer was
- not 0
- excessCollsns –95 hardware error
- reqFailed –1096 request to contact router failed; retry count exceeded
- cbNotFound –1102 control block not found; no pending asynchronous calls
- CBNotFound –1102 ERead not active
- reqAborted –1105 ERdCancel function called for this ERead
- errDSPQueueSize –1274 send or receive queue is too small
- errFwdReset –1275 read terminated by forward reset
- errAttention –1276 attention message too long
- errOpening –1277 attempt to open connection failed
- errState –1278 bad connection state for this operation
- errAborted –1279 request aborted by dspRemove or dspClose command
- errRefNum –1280 bad connection reference number
- buf2SmallErr –3101 packet too large for buffer; partial data returned
- _______________________________________________________________________________
-
- æKY Assembly-language…Information…for…AppleTalk
- æC »Assembly-language Information AppleTalk Manager
- _______________________________________________________________________________
-
- Constants
-
- mainVersion EQU 1
- subVersion EQU 1
- ;client control codes
- dspInit EQU 255 ;create a new connection end
- dspRemove EQU 254 ;remove a connection end
- dspOpen EQU 253 ;open a connection
- dspClose EQU 252 ;close a connection
- dspCLInit EQU 251 ;create a connection listener
- dspCLRemove EQU 250 ;remove a connection listener
- dspCLListen EQU 249 ;post a listener request
- dspCLDeny EQU 248 ;deny an open connection request
- dspStatus EQU 247 ;get status of connection end
- dspRead EQU 246 ;read data from the connection
- dspWrite EQU 245 ;write data on the connection
- dspAttention EQU 244 ;send an attention message
- dspOptions EQU 243 ;set connection end options
- dspReset EQU 242 ;forward reset the connection
- dspNewCID EQU 241 ;generate a cid for a connection end
- ;open connection modes
- ocRequest EQU 1 ;request a connection with remote
- ocPassive EQU 2 ;wait for a connection request from remote
- ocAccept EQU 3 ;accept request as delivered by listener
- ocEstablish EQU 4 ;consider connection to be open
- ;connection states
- sListening EQU 1 ;for connection listeners
- sPassive EQU 2 ;waiting for a connection request from remote
- sOpening EQU 3 ;requesting a connection with remote
- sOpen EQU 4 ;connection is open
- sClosing EQU 5 ;connection is being torn down
- sClosed EQU 6 ;connection end state is closed
- ;client event flags (bit-mask)
- eClosed EQU $80 ;received connection closed advice
- eTearDown EQU $40 ;closed due to broken connection
- eAttention EQU $20 ;received attention message
- eFwdReset EQU $10 ;received forward reset advice
- ;miscellaneous equates
- attnBufSize EQU 570 ;size of client attention message
- minDSPQueueSize EQU 100 ;minimum size for both receive and send queues
- ;connection control block equates & size
- ccbLink EQU 0 ;link to next ccb
- refNum EQU ccbLink+4 ;user reference number
- state EQU refNum+2 ;state of the connection end
- userFlags EQU state+2 ;flags for unsolicited connection events
- localSocket EQU userFlags+1 ;socket number of this connection end
- remoteAddress EQU localSocket+1 ;internet address of remote end
- attnCode EQU remoteAddress+4 ;attention code received
- attnSize EQU attnCode+2 ;size of received attention data
- attnPtr EQU attnSize+2 ;ptr to received attention data
- ccbSize EQU attnPtr+224 ;total byte size of ccb
- ;adsp queue element equates & size
- csQStatus EQU CSParam ;adsp internal use
- csCCBRef EQU csQStatus+4 ;refnum of ccb
- ;dspInit, dspCLInit
- csCCBPtr EQU csCCBRef+2 ;pointer to connection control block
- csUserRtn EQU csCCBPtr+4 ;client routine to call on event
- csSendQSize EQU csUserRtn+4 ;size of send queue (0..64K bytes)
- csSendQueue EQU csSendQSize+2 ;client passed send queue buffer
- csRecvQSize EQU csSendQueue+4 ;size of receive queue (0..64 KBb)
- csRecvQueue EQU csRecvQSize+2 ;client passed receive queue buffer
- csAttnPtr EQU csRecvQueue+4 ;client passed receive attention buffer
- csLocSkt EQU csAttnPtr+4 ;local socket number
- ;dspOpen, dspCLListen, dspCLDeny
- csLocCID EQU csCCBRef+2 ;local connection id
- csRemCID EQU csLocCID+2 ;remote connection id
- csRemAddr EQU csRemCID+2 ;address of remote end
- csFltrAddr EQU csRemAddr+4 ;address filter
- csSendSeq EQU csFltrAddr+4 ;local send sequence number
- csSendWdw EQU csSendSeq+4 ;send window size
- csRecvSeq EQU csSendWdw+2 ;receive sequence number
- csAttnSendSeq EQU csRecvSeq+4 ;attention send sequence number
- csAttnRecvSeq EQU csAttnSendSeq+4 ;attention receive sequence number
- csOCMode EQU csAttnRecvSeq+4 ;open connection mode
- csOCInterval EQU csOCMode+1 ;open connection request retry interval
- csOCMaximum EQU csOCInterval+1 ;open connection request retry maximum
- ;dspClose, dspRemove
- csAbort EQU csCCBRef+2 ;abort connection immediately if non-zero
- ;dspStatus
- csSQPending EQU csCCBPtr+4 ;pending bytes in send queue
- csSQFree EQU csSQPending+2 ;available buffer space in send queue
- csRQPending EQU csSQFree+2 ;pending bytes in receive queue
- csRQFree EQU csRQPending+2 ;available buffer space in receive queue
- ;dspRead, dspWrite
- csReqCount EQU csCCBRef+2 ;requested number of bytes
- csActCount EQU csReqCount+2 ;actual number of bytes
- csDataPtr EQU csActCount+2 ;pointer to data buffer
- csEOM EQU csDataPtr+4 ;indicates logical end of message
- csFlush EQU csEOM+1 ;send data now dspAttention
- csAttnCode EQU csCCBRef+2 ;client attention code
- csAttnSize EQU csAttnCode+2 ;size of attention data
- csAttnData EQU csAttnSize+2 ;pointer to attention data
- csAttnInterval EQU csAttnData+4 ;retransmit timer in 10-tick intervals
- ;dspOptions
- csSendBlocking EQU csCCBRef+2 ;quantum for data packets
- csSendTimer EQU csSendBlocking+2 ;send timer in 10-tick intervals
- csRtmtTimer EQU csSendTimer+1 ;retransmit timer in 10-tick intervals
- csBadSeqMax EQU csRtmtTimer+1 ;threshold for sending retransmit advice
- csUseCheckSum EQU csBadSeqMax+1 ;use ddp packet checksum dspNewCID
- csNewCID EQU csCCBRef+2 ;new connection id returned
- dspPBSize EQU 68 ;byte size of largest DSP param block
- _______________________________________________________________________________
-
-
- æKY BinaryDecimalConversion
- æC
- THE BINARY-DECIMAL CONVERSION PACKAGE
- _______________________________________________________________________________
-
- About…The…Binary-DecimalConversion…Chapter
- Binary-Decimal…Conversion…Package…Routines
- Summary…of…the…Binary-Decimal…Conversion…Package
- _______________________________________________________________________________
-
-
-
- æKY About…The…Binary-DecimalConversion…Chapter
- æC »ABOUT THIS CHAPTER BinaryDecimalConversion
- _______________________________________________________________________________
-
- This chapter describes the Binary-Decimal Conversion Package, which contains five
- routines. One converts an integer from its internal (binary) form to a string that
- represents its decimal (base 10) value; the other converts a decimal string to the
- corresponding integer.
-
- Three new routines have been added to the Binary-Decimal Conversion Package for the
- Macintosh Plus. These routines supplement the Floating-Point Arithmetic and Transcendental
- Functions Packages in providing the the Standard Apple Numeric Environment (SANE) for
- the Macintosh.
-
- Detailed documentation for these new routines is included with the rest of the SANE
- documentation in the Apple Numerics Manual—in particular, see the chapter
- “Conversions” in Part I and the three chapters “Conversions”, “Numeric Scanner and
- Formatter”, and “Examples” in Part III.
-
- The new routines, two numeric scanners and a numeric formatter, are intended for
- programmers with special needs beyond what their development language provides. For
- example, developers of programming languages can use these routines to implement the
- floating-point I/O routines—such as read and write for Pascal or scanf and printf for
- C—that are appropriate for their particular languages. The scanners can be used for
- scanning numbers embedded in text and for numbers received character by character.
- The scanners differ only in that one accepts a pointer to a Pascal strings (with an
- initial length byte) as input, while the other accepts a pointer to the first character
- of a character stream.
-
- The scanners convert ASCII string representations of numbers into SANE decimal records.
- The formatter converts SANE decimal records into ASCII string representations. The
- Floating-Point Arithmetic Package converts between this decimal record format and the
- SANE binary data formats.
-
- The three routines handle the usual number representations, like –1.234 and
- 5e–7, throughout the range and precision of the extended data format. They also
- handle the special NaN, infinity, and signed-zero representations specified by the
- IEEE Floating-Point Standard.
-
- You should already be familiar with packages in general, as described in the Package
- Manager chapter.
-
- _______________________________________________________________________________
-
-
- æKY Binary-Decimal…Conversion…Package…Routines
- æC »BINARY-DECIMAL CONVERSION PACKAGE ROUTINES BinaryDecimalConversion
- _______________________________________________________________________________
-
- The Binary-Decimal Conversion Package is contained in the ROM, beginning with the
- 128K ROM. The routines are register-based, so the Pascal form of each is followed by
- a box containing information needed to use the routine from assembly language.
-
- Assembly-language note: The trap macro for the Binary-Decimal Conversion
- Package is _Pack7. The routine selectors are as
- follows:
-
- numToString .EQU 0
- stringToNum .EQU 1
-
- PROCEDURE NumToString (theNum: LONGINT; VAR theString: Str255);
-
- On entry A0: pointer to theString (preceded by length byte)
- D0: theNum (long word)
- On exit A0: pointer to theString
-
- NumToString converts theNum to a string that represents its decimal value, and returns
- the result in theString. If the value is negative, the string begins with a minus
- sign; otherwise, the sign is omitted. Leading zeroes are suppressed, except that the
- value 0 produces '0'. For example:
-
- theNum theString
-
- 12 '12'
- –23 '–23'
- 0 '0'
-
- PROCEDURE StringToNum (theString: Str255; VAR theNum: LONGINT);
-
- On entry A0: pointer to theString (preceded by length byte)
- On exit D0: theNum (long word)
-
- Given a string representing a decimal integer, StringToNum converts it to the corresponding
- integer and returns the result in theNum. The string may begin with a plus or minus
- sign. For example:
-
- theString theNum
-
- '12' 12
- '–23' –23
- '–0' 0
- '055' 55
-
- The magnitude of the integer is converted modulo 2^32, and the 32-bit result is
- negated if the string begins with a minus sign; integer overflow occurs if the magnitude
- is greater than 2^31–1. (Negation is done by taking the two’s complement—reversing
- the state of each bit and then adding 1.) For example:
-
- theString theNum
-
- '2147483648' (magnitude is 2^31) –2147483648
- '–2147483648' –2147483648
- '4294967295' (magnitude is 2^32–1) –1
- '–4294967295' 1
-
- StringToNum doesn’t actually check whether the characters in the string are between
- '0' and '9'; instead, since the ASCII codes for '0' through '9' are $30 through $39,
- it just masks off the last four bits and uses them as a digit. For example, '2:' is
- converted to the number 30 because the ASCII code for ':' is $3A. Spaces are treated
- as zeroes, since the ASCII code for a space is $20. Given that the ASCII codes for
- 'C', 'A', and 'T' are $43, $41, and $54, respectively, consider the following examples:
-
- theString theNum
-
- 'CAT' 314
- '+CAT' 314
- '–CAT' –314
-
- _______________________________________________________________________________
-
-
- æKY Summary…of…the…Binary-Decimal…Conversion…Package
- æC »SUMMARY OF THE BINARY-DECIMAL CONVERSION PACKAGE BinaryDecimalConversion
- _______________________________________________________________________________
-
- Routines
-
- PROCEDURE NumToString (theNum: LONGINT; VAR theString: Str255);
- PROCEDURE StringToNum (theString: Str255; VAR theNum: LONGINT);
-
- _______________________________________________________________________________
-
- Assembly-Language Information
-
- Constants
-
- ; Routine selectors
-
- numToString .EQU 0
- stringToNum .EQU 1
-
- Routines
-
- Name On entry On exit
-
- NumToString A0: ptr to theString A0: ptr to theString
- (preceded by length byte)
- D0: theNum (long)
- StringToNum A0: ptr to theString D0: theNum (long)
- (preceded by length byte)
-
- Trap Macro Name
-
- _Pack7
-
-
- æKY ColorManager
- æC
- THE COLOR MANAGER
- _______________________________________________________________________________
-
- About…The…ColorManager…Chapter
- About…the…Color…Manager
- Using…the…Color…Manager
- Color…Manager…Routines
- Custom…Search…and…Complement…Functions
- Summary…of…the…Color…Manager
- _______________________________________________________________________________
-
-
-
- æKY About…The…ColorManager…Chapter
- æC »ABOUT THIS CHAPTER ColorManager
- _______________________________________________________________________________
-
- The Color Manager supplies color-selection support for Color QuickDraw on the Macintosh
- II. The software described in this chapter allows specialized applications to fine-tune
- the color-matching algorithms, and also provides utility functions that are rarely
- used by applications.
-
- An understanding of Color QuickDraw concepts, terminology, and data structures is
- essential when using the material in this chapter. You should be familiar with RGB
- color, pixel maps, pixel patterns, and other material introduced in the Color QuickDraw
- chapter. You should also be familiar with the material in the Graphics Devices chapter,
- since the Color Manager routines work on the device level.
-
- Keep in mind that Color Manager routines are the intermediary between high-level
- software such as Color QuickDraw, the Palette Manager, and the Color Picker, and the
- lower-level video devices. The majority of applications will never need to use the
- Color Manager routines directly.
-
- Reader’s guide: The material in this chapter is largely for informational
- purposes only, since Color QuickDraw, the Palette Manager,
- and the other color Toolbox routines provide a detailed and
- consistent way to add color to Macintosh programs.
-
- _______________________________________________________________________________
-
-
- æKY About…the…Color…Manager
- æC »ABOUT THE COLOR MANAGER ColorManager
- _______________________________________________________________________________
-
- The Color Manager is optimized to work with graphics hardware that utilizes a Color
- Look-up Table (CLUT), a data structure that maps color indices, specified using
- QuickDraw, into actual color values. The exact color capabilities of the Macintosh
- II depend on the particular video card used. There are three kinds of devices:
-
- • CLUT devices contain hardware that converts an arbitrary pixel value
- stored in the frame buffer to some actual RGB video value, which is
- changeable. The pixel value could be the index to any of the colors
- in the current color set for the device, and the color set itself
- can be changed.
- • Fixed devices also convert a pixel value to some actual RGB video
- value, but the hardware colors can’t be changed. The pixel value
- could be the index to any of the colors in the color set, but the
- color set itself always remains the same.
- • Direct devices have a direct correlation between the value placed in
- the frame buffer and the color you see on the screen. The value placed
- in the frame buffer would produce the same color every time. Direct
- devices aren’t supported in the initial release of Color QuickDraw.
-
- Applications that limit themselves to a small set of colors can use them simply and
- easily from QuickDraw, with a minimum of overhead. Color QuickDraw accesses the
- Color Manager to obtain the best available color matches in the lookup table. Applications
- such as color painting and animation programs, which need greater control over the
- precise colors they use, can use the Palette Manager to allocate part of the color
- table for their own exclusive use. The Palette Manager, described in a later chapter,
- is useful for most applications that use shared color resources, imaging, or color
- table animation. The Palette Manager is used whenever color is used for objects
- within windows, while the Color Manager operates on the device level.
-
- Note: Palette Manager routines operate transparently across multiple
- screens, while Color Manager routines do not. Therefore, always
- use Palette Manager routines for applications that will run on
- multiple screens or in a multitasking environment.
-
- The sections that follow describe how the Color Manager converts the RGB values
- specified using Color QuickDraw into the actual colors available on a device. The
- pixel value, specifying the number of bits per pixel, is set using the Control Panel.
-
- _______________________________________________________________________________
-
- »Graphics Devices
-
- As with Color QuickDraw, the Color Manager accesses a particular graphics device
- through a data structure known as a gDevice record. Each gDevice record stores information
- about a particular graphics device; after this record is initialized, the device
- itself is known to the Color Manager and QuickDraw as a gDevice. See the Graphics
- Devices chapter for more details on gDevice format and on the routines that allow an
- application to access a given device. Remember that a gDevice is a logical device,
- which the software treats the same whether it is a video card, a display device, or
- an offscreen pixel map.
-
- _______________________________________________________________________________
-
- »Color Table Format
-
- The complete set of colors in use at a given time for a particular gDevice is summarized
- in a color table record. Its format is as follows:
-
- TYPE
- CTabHandle = ^CTabPtr;
- CTabPtr = ^ColorTable;
- ColorTable = RECORD
- ctSeed: LONGINT; {unique identifier from table}
- ctFlags: INTEGER; {high bit is set for a gDevice, }
- { clear for a pixMap}
- ctSize: INTEGER; {Number of entries in table-1}
- ctTable: cSpecArray
- END;
-
- Field descriptions
-
- ctSeed The ctSeed field is similar to a version identifier number for
- a color table. If a color table is created by an application, it
- should call GetCTSeed to obtain this identifier. The ctSeed should
- be some unique number higher than minSeed, a predefined constant
- with a value of 1023. If a color table is created from a resource,
- its resource number will be used as the initial ctSeed. For 'CLUT'
- resource, the range of resource numbers should be 0–1023.
-
- ctFlags The ctFlags field is significant for gDevices only. It contains
- flags that describe the format of the ctTable. Currently, only
- the high bit is defined; all others are reserved. Color tables
- that are part of the gDevice structure always have this bit set.
- Color tables that are part of pixMaps have this bit clear. Each
- gDevice has its own pixMap, which has a color table.
-
- ctSize The ctSize field contains the number of entries in the color
- table minus one. All counts on color table entries are zero based.
-
- ctTable The ctTable field contains a cSpecArray, which is an array of
- ColorSpec entries. Notice that each entry in the color table is
- a ColorSpec, not simply an RGBColor. The type ColorSpec is
- composed of an integer value and an RGB color, as shown in the
- following specification. A color table may include a number of
- ColorSpec records.
-
- TYPE
- cSpecArray = ARRAY [0..0] OF ColorSpec;
- ColorSpec = RECORD
- value : INTEGER; {Color representation}
- rgb : RGBColor {Color value}
- END;
- RGBColor = RECORD
- red : INTEGER; {Red component}
- green : INTEGER; {Green component}
- blue : INTEGER {Blue component}
- END;
-
- In gDevice color tables, the colorSpec.value field is reserved for use by the Color
- Manager and Palette Manager. Their interpretation and values are different than the
- color tables contained in pixMaps.
-
- •••Refer to Figure 1.•••
-
- Figure 1–Color Table Format
-
- Note that the colorSpec.value field of the record is only word size (16 bits), even
- though color index values (as returned by Color2Index) may be long words. The current
- implementation of Color QuickDraw only supports 16 bits. The components in an RGBColor
- are left-justified rather than right-justified in a word. Video drivers should respect
- this convention and extract the appropriate number of bits from the high order side
- of the component. For example, the Apple Graphics Card uses only the most significant
- eight bits of each component of the RGBColor record.
-
- _______________________________________________________________________________
-
- »Inverse Tables
-
- Reader’s guide: The material in this section is provided for informational
- and debugging purposes, since most programs won’t need to
- use inverse tables.
-
- For normal drawing, Color QuickDraw takes all specifications as absolute RGB triples,
- by means of the RGBColor record. Internally, these absolute specifications are converted
- to the appropriate values to be written into the video card. For direct devices, the
- RGB is separated into its red, green, and blue components, and each of these is
- written to the video card. On CLUT and fixed devices, however, there isn’t always a
- direct relationship between the specified RGB and the index value written into the
- frame buffer; in fact, on CLUT devices, the best-match index value may change dynamically
- as the colors available in the hardware are changed. On these types of devices, Color
- QuickDraw uses the Color Manager to find the best matches among the colors currently
- available.
-
- The method used to determine the best available match can be specified by the application
- or the system on a gDevice by gDevice basis. By default, on CLUT and fixed devices, a
- special data structure called an inverse table is created. An inverse table is a
- table arranged in such a manner that, given an arbitrary RGB color, the pixel value
- can be very rapidly looked up.
-
- In the default case, a certain number of the most significant bits of red, green, and
- blue are extracted, then concatenated together to form an index into the inverse
- table. At this location is the “best” match to the specified color. The number of
- bits per color channel that are used to construct this index is known as the resolution
- of the inverse table, and can be 3, 4, or 5 bits per channel. As the resolution of
- the inverse table increases, the number of permutations of possible colors increases,
- as does the size of the inverse table. Three-bit tables occupy 512 bytes, 4-bit
- tables (the default) occupy 4K bytes, and 5-bit tables occupy 32K bytes.
-
- A disadvantage of this method is that certain colors that are “close” together can
- become hidden when they differ only in bits that weren’t used to construct the inverse
- table index. For example, even if the color table were loaded with 256 levels of
- gray, a 4-bit inverse table can only discriminate among 16 of the levels. To solve
- this problem without having to use special-case sets of colors with hidden colors,
- inverse tables carry additional information about how to find colors that differ only
- in the less significant bits. As a result, when the Color2Index routine is called, it
- can find the best match to the full 48-bit resolution available in a colorSpec. Since
- examining the extra information takes time, certain parts of Color QuickDraw, notably
- drawing in the arithmetic transfer modes, don’t use this information, and hence won’t
- find the hidden colors.
-
- In most cases, when setting colors using RGBForeColor and RGBBackColor, and when
- using CopyBits to transfer pixMaps, inverse tables of four bits are sufficient. When
- using arithmetic transfer modes with certain color tables that have closely-spaced
- colors, the screen appearance may be improved by specifying inverse tables at 5-bit
- resolution. Because the format of inverse tables is subject to change in the future,
- or may not be present on certain devices, applications should not assume the structure
- of the data.
-
- The data in inverse tables remains valid as long as the color table from which it was
- built remains unchanged. When a color table is modified, the inverse table must be
- rebuilt, and the screen should be redrawn to take advantage of this new information.
- Rather than being reconstructed when the color table is changed, the inverse table is
- marked invalid, and is automatically rebuilt when next accessed.
-
- Rather than testing each entry of the color table to see if it has changed, the
- color-matching code compares the ctSeed of the current gDevice’s colorTable against
- the iTabSeed of that gDevice’s inverse table. Each routine that modifies the colorTable
- (with the exception of RestoreEntries) increments the ctSeed field of that colorTable.
- If the ctSeed and the iTabSeed don’t match, the inverse table is reconstructed for
- that gDevice.
-
- Note: Under normal circumstances, all invalidations are posted and serviced
- transparently to the application. This method of invalidation is the
- same as that used to invalidate expanded patterns and cursors elsewhere
- in Color QuickDraw.
-
- In certain cases, it may be useful to override the inverse table matching code with
- custom routines that have special matching rules. See the section titled
- “Custom Search and Complement Procedures” for more details.
-
- The Color Manager performs a color table look-up in the following manner:
-
- 1. Builds a table of all possible RGB values;
- 2. For each position in the table, attempts to get the closest match;
- 3. Reduces the resolution of the lookup to four bits when constructing
- the table, but later adds information to get a better resolution.
-
- The Color Manager performs this table-building sequence whenever colors are requested
- by Color QuickDraw, the Color Picker, or the Palette Manager. This isn’t the only
- color matching method available; a custom search procedure, for example, may not have
- an inverse table. (See the section titled “Custom Search and Complement Procedures”
- for more information.) However, inverse tables are the default method for color
- matching.
-
- When using an inverse table, the table is indexed by concatenating together the
- high-order bits of the three desired color components; iTabRes tells how many bits of
- each component are significant. The format of an inverse table is shown below:
-
- TYPE
- ITabHandle = ^ITabPtr;
- ITabPtr = ^ITab;
- ITab = RECORD
- iTabSeed: LONGINT; {copy of color table seed}
- iTabRes: INTEGER; {resolution of table}
- iTTable: ARRAY[0..0] OF SignedByte {byte color }
- { table index values}
- END;
-
- The size of an index table in bytes is 2^3*iTabRes. The table below shows a sample
- index table:
-
- resolution RGB color inverse-table size
- index
- 4-bit red=$1234,
- green=$5678,
- blue=$9ABC $0159 2^12 = 4K bytes
-
- 5-bit red=$1234,
- green=$5678,
- blue=$9ABC $0953 2^15 = 32K bytes
-
- MakeITable only supports 3-bit, 4-bit, and 5-bit resolution. Five bits is the maximum
- possible resolution, since the indices into a 6-bit table would have to be 18 bits
- long, more than a full word.
-
- _______________________________________________________________________________
-
-
- æKY Using…the…Color…Manager
- æC »USING THE COLOR MANAGER ColorManager
- _______________________________________________________________________________
-
- In the simplest cases, use of the Color Manager is transparent when invoking the new
- Color QuickDraw routines. Using RGBForeColor and RGBBackColor, the program requests
- an RGB color for either the foreground or background. For instance, the following
- code requests an RGB color of red and sets it in the cGrafPort:
-
- myColor.red:=$FFFF;
- myColor.green:=0;
- myColor.blue:=0;
- RGBForeColor(myColor); {set pen red}
- FrameRect(myRect); {draw in red}
-
- Internally the Color Manager finds the best match to a color in TheGdevice’s current
- color table, and sets up the current cGrafPort to draw in this color. At this point,
- drawing operations can proceed using the selected colors.
-
- The Color Manager routines described in this chapter are designed to operate on a
- single gDevice. The Palette Manager can perform most of these operations across
- multiple gDevices. Since the Palette Manager provides more general and portable
- functionality, applications should use Palette Manager routines whenever possible.
-
- The SetEntries routine is used to change any part of or all of the entries in a
- device’s hardware Color Look-Up Table. The SaveEntries and RestoreEntries routines
- can make temporary changes to the color table under very specialized circumstances
- (such as a color selection dialog within an application). These routines aren’t
- needed under normal application circumstances.
-
- SaveEntries allows any combination of colorSpecs to be copied into a special colorTable.
- RestoreEntries replaces the table created by SaveEntries into the graphics device.
- Unlike SetEntries, these routines don’t perform invalidations of the device’s colorTable,
- so they avoid causing invalidations of cached data structures. When these routines
- are used, the application must take responsibility for rebuilding and restoring
- auxiliary structures as necessary.
-
- By convention, when using SetEntries or RestoreEntries, white should be located at
- color table position 0, and black should be stored in the last color table position
- available, whether it is 1, 3, 15, or 255. The Palette Manager also enforces this
- convention.
-
- For precise control over color, or for dedicated color table entries, the Color
- Manager routines maintain special information in device color tables. Using ProtectEntry
- and ReserveEntry, an entry may be protected, which prevents SetEntries from further
- changing the entry, or reserved, which makes the entry unavailable to be matched by
- RGBForeColor and RGBBackColor. Routines that change the device table (SetEntries,
- ProtectEntry, and ReserveEntry, but not RestoreEntries) will perform the appropriate
- invalidations of QuickDraw data structures. The application must then redraw where
- necessary.
-
- To inquire if a color exists in a color table, use RealColor. This tells whether an
- arbitrary color actually exists in the table for that gDevice.
-
- Color2Index returns the index in the current device’s colorTable that is the best
- match to the requested color. Index2Color performs the opposite function—it returns
- the RGB of a particular index value. These routines can be useful when making copies
- of the screen frame buffer. InvertColor finds the complement of the provided color.
- GetSubTable performs a group Color2Index on a colorTable.
-
- _______________________________________________________________________________
-
-
- æKY Color…Manager…Routines
- æC »COLOR MANAGER ROUTINES ColorManager
- _______________________________________________________________________________
-
- The routines used for color drawing are covered in the chapter “Color
- QuickDraw”. The Color Manager includes routines for color conversion, color table
- management, and error handling.
-
- _______________________________________________________________________________
-
- »Color Conversion
-
- FUNCTION Color2Index (rgb: RGBColor): LONGINT;
-
- The Color2Index routine finds the best available approximation to a given absolute
- color, using the list of search procedures in the current device record. It returns a
- longint, which is a pixel value padded with zeros in the high word. Since the colorSpec.value
- field is only a word, the result returned from Color2Index must be truncated to fit
- into a colorSpec. In pixMaps the
- .value is the low-order word of this index.
-
- Color2Index shouldn’t be called from a custom search procedure.
-
- PROCEDURE Index2Color (index: LONGINT; VAR rgb: RGBColor);
-
- The Index2Color routine finds the RGB color corresponding to a given color table
- index. The desired pixel value is passed and the corresponding RGB value is returned
- in RGB. The routine takes a longint, which should be a pixel value padded with zeros
- in the high word (normally the compiler does this automatically). Normally, the RGB
- from the current device color table corresponding to the index is returned as the
- RGBColor. Notice that this is not necessarily the same color that was originally
- requested via RGBForeColor, RGBBackColor, SetCPixel, or Color2Index. This RGB is read
- from the current gDevice color table.
-
- PROCEDURE InvertColor (VAR theColor: RGBColor);
-
- The InvertColor routine finds the complement of an absolute color, using the list of
- complement procedures in the current device record. The default complement procedure
- uses the 1’s complement of each component of the requested color.
-
- FUNCTION RealColor (color: RGBColor) : BOOLEAN;
-
- The RealColor routine tells whether a given absolute color actually exists in the
- current device’s color table. This decision is based on the current resolution of the
- inverse table. For example, if the current iTabRes is four, RealColor returns TRUE if
- there exists a color that exactly matches the top four bits of red, green, and blue.
-
- PROCEDURE GetSubTable (myColors: CTabHandle; iTabRes:INTEGER;
- targetTbl: CTabHandle);
-
- The GetSubTable routine takes a ColorTable pointed at by myColors, and maps each RGB
- value into its nearest available match for each target table. These best matches are
- returned in the colorSpec.value fields of myColors. The values returned are best
- matches to the RGBColor in targetTbl and the returned indices are indices into targetTbl.
- Best matches are calculated using Color2Index and all applicable rules apply. A
- temporary inverse table is built, and then discarded. ITabRes controls the resolution
- of the iTable that is built. If targetTbl is NIL, then the current device’s color
- table is used, and the
- device’s inverse table is used rather than building a new one. To provide a different
- resolution than the current inverse table, provide an explicit targetTbl parameter;
- don’t pass a NIL parameter.
-
- Warning: Depending on the requested resolution, building the inverse table
- can require large amounts of temporary space in the application
- heap: twice the size of the table itself, plus a fixed overhead
- for each inverse table resolution of 3–15K bytes.
-
- PROCEDURE MakeITable (colorTab: CTabHandle; inverseTab: ITabHandle;
- res: INTEGER);
-
- The MakeITable routine generates an inverse table based on the current contents of
- the color table pointed to by CTabHandle, with a resolution of res bits per channel.
- Reserved color table pixel values are not included in the resultant color table.
- MakeITable tests its input parameters and will return an error in QDError if the
- resolution is less than three or greater than five. Passing a NIL parameter to CTabHandle
- or ITabHandle substitutes an appropriate handle from the current gDevice, while
- passing 0 for res substitutes the current gDevice’s preferred table resolution. These
- defaults can be used in any combination with explicit values, or with NIL parameters.
-
- This routine allows maximum precision in matching colors, even if colors in the color
- table differ by less than the resolution of the inverse table. Five-bit inverse
- tables are not needed when drawing in normal QuickDraw modes. However, the new QuickDraw
- transfer modes (add, subtract, blend, etc.) may require a
- 5-bit inverse table for best results with certain color tables. MakeITable returns a
- QDError if the destination inverse table memory cannot be allocated. The 'mitq'
- resource governs how much memory is allocated for temporary internal structures; this
- resource type is for internal use only.
-
- Warning: Depending on the requested resolution, building the inverse table
- can require large amounts of temporary space in the application
- heap: twice the size of the table itself, plus a fixed overhead
- for each inverse table resolution of 3–15K bytes.
-
- _______________________________________________________________________________
-
- »Color Table Management
-
- FUNCTION GetCTSeed : LONGINT;
-
- The GetCTSeed function returns a unique seed value that can be used in the ctSeed
- field of a color table created by an application. This seed value guarantees that the
- color table will be recognized as distinct from the destination, and that color table
- translation will be performed properly. The return value will be greater than the
- value stored in minSeed.
-
- PROCEDURE ProtectEntry (index: INTEGER; protect: BOOLEAN);
-
- The ProtectEntry procedure protects or removes protection from an entry in the current
- device’s color table, depending on the value of the protect parameter. A protected
- entry can’t be changed by other clients. It returns a protection error if it attempts
- to protect an already protected entry. However, it can remove protection from any
- entry.
-
- PROCEDURE ReserveEntry (index: INTEGER; reserve: BOOLEAN);
-
- The ReserveEntry procedure reserves or dereserves an entry in the current color
- table, depending on the value of the reserve parameter. A reserved entry cannot be
- matched by another client’s search procedure, and will never be returned to another
- client by Color2Index or other routines that depend on it
- (such as RGBForeColor, RGBBackColor, SetCPixel, and so forth). You could use this
- routine to selectively protect a color for color table animation.
-
- ReserveEntry copies the low byte of gdID into the low byte of ColorSpec.value when
- reserving an entry, and leaves the high byte alone. It acts like a selective protection,
- and does not allow any changes if the current gdID is different than the one in the
- colorSpec.value field of the reserved entry. If a requested match is already reserved,
- ReserveEntry returns a protection error. Any entry can be dereserved.
-
- PROCEDURE SetEntries(start, count: INTEGER; aTable: CSpecArray);
-
- The SetEntries procedure sets a group of color table entries for the current gDevice,
- starting at a given position for the specified number of entries. The pointer aTable
- points into a cSpecArray, not into a color table. The colorSpec.value field of the
- entries must be in the logical range for the target card’s assigned pixel depth.
- Thus, with a 4-bit pixel size, the colorSpec.value fields should be in the range 1 to
- 15. With an 8-bit pixel size the range is 0 to 255. Note that all values are zero-based;
- for example, to set three entries, pass two in the count parameter.
-
- Note: Palette Manager routines should be used instead of the SetEntries
- routine for applications that will run in a multiscreen or
- multitasking environment.
-
- The SetEntries positional information works in logical space, rather than in the
- actual memory space used by the hardware. Requesting a change at position four in the
- color table may not modify color table entry four in the hardware, but it does correctly
- change the color on the screen for any pixels with a value of four in the video card.
- The SetEntries mode characterized by a start position and a length is called sequence
- mode. In this case, new colors are sequentially loaded into the hardware in the same
- order as the aTable, the clientID fields for changed entries are copied from the
- current device’s gdID field, and the colorSpec.value fields are ignored.
-
- The other SetEntries mode is called index mode. It allows the cSpecArray to specify
- where the data will be installed on an entry-by-entry basis. To use this mode, pass
- –1 for the start position, with a valid count and a pointer to the cSpecArray. Each
- entry is installed into the color table at the position specified by the colorSpec.value
- field of each entry in the cSpecArray. In the current device’s color table, all
- changed entries’ colorSpec.value fields are assigned the gdID value.
-
- When color table entries are changed, all cached fonts are invalidated, and the seed
- number is changed so that the next drawing operation will rebuild the inverse table.
- If any of the requested entries are protected or out of range, a protection error is
- returned, and nothing happens. If a requested entry is reserved, it can only be
- changed if the current gdID matches the low byte of the intended ColorSpec.value
- field.
-
- PROCEDURE SaveEntries (srcTable: CTabHandle; ResultTable: CTabHandle;
- VAR selection: ReqListRec);
-
- SaveEntries saves a selection of entries from srcTable into resultTable. The entries
- to be set are enumerated in the selection parameter, which uses the ReqListRec data
- structure shown below. (These values are offsets into colorTable, not the contents of
- the colorSpec.value field.)
-
- TYPE
- ReqListRec = RECORD
- reqLSize: INTEGER; {request list size –1}
- reqLData: ARRAY [0..0] of INTEGER {request list data}
- END;
-
- If an entry is not present in srcTable, then that position of the requestList is set
- to colReqErr, and that position of resultTable has random values returned. If one or
- more entries are not found, then an error code is posted to QDError; however, for
- every entry in selection which is not colReqErr, the values in resultTable are valid.
- Note that srcTable and selection are assumed to have the same number of entries.
-
- SaveEntries optionally allows NIL as its source color table parameter. If NIL is
- used, the current device’s color table is used as the source. The output of SaveEntries
- is the same as the input for RestoreEntries, except for the order.
-
- PROCEDURE RestoreEntries (srcTable:CTabHandle;DstTable:CTabHandle;
- VAR selection:ReqListRec);
-
- RestoreEntries sets a selection of entries from srcTable into dstTable, but doesn’t
- rebuild the inverse table. The dstTable entries to be set are enumerated in the
- selection parameter, which uses the ReqListRec data structure shown in the SetEntries
- routine description. (These values are offsets into the srcTable, not the contents of
- the colorSpec.value field.)
-
- If a request is beyond the end of the dstTable, that position of the requestList is
- set to colReqErr, and an error is returned. Note that srcTable and selection are
- assumed to have the same number of entries.
-
- If dstTbl is NIL, or points to the device color table, the current device’s color
- table is updated, and the hardware is updated to these new colors. The seed is not
- changed, so no invalidation occurs (this may cause RGBForeColor to act strangely).
- This routine ignores protection and reservation of color table entries.
-
- Generally, the Palette Manager is used to give an application its own set of colors;
- use of RestoreEntries should be limited to special-purpose applications. RestoreEntries
- allows you to change the colorTable without changing the ctSeed for the affected
- colorTable. You can execute the application code and then use RestoreEntries to put
- the original colors back in. However, in some cases things in the background may
- appear in the wrong colors, since they were never redrawn. To avoid this, the application
- must build its own new inverse table and redraw the background. If RestoreEntries
- were then used, the ctSeed would have to be explicitly changed to clean up correctly.
-
- _______________________________________________________________________________
-
- »Error Handling
-
- FUNCTION QDError: INTEGER;
-
- The QDError routine returns the error result from the last QuickDraw or Color Manager
- call. This routine is even more useful with 32-Bit QuickDraw. It is important that
- you check for errors after every QuickDraw call. For more information, see the
- 32-Bit QuickDraw documentation.
-
- _______________________________________________________________________________
-
-
- æKY Custom…Search…and…Complement…Functions
- æC »CUSTOM SEARCH AND COMPLEMENT FUNCTIONS ColorManager
- _______________________________________________________________________________
-
- The custom search function allows an application to override the inverse table matching
- code. The desired color is specified in the RGBColor field of a ColorSpec record and
- passed via a pointer on the stack; the procedure returns the corresponding pixel
- value in the ColorSpec.value field.
-
- A custom search routine can provide its own matching rules. For instance, you might
- want to map all levels of green to a single green on a monitor. To do this, you could
- write and install a custom search procedure that is passed the RGB under question by
- the Color Manager. It can then analyze the color, and if it decides to act on this
- color, it can return the index of the desired shade of green. Otherwise, it can pass
- the color back to the Color Manager for matching, using the normal inverse table
- routine.
-
- Many applications can share the same graphics device, each with its own custom search
- procedure. The procedures are chain elements in a linked list beginning in the
- gdSearchProc field of the gDevice port:
-
- TYPE
- SProcHndl = ^SProcPtr;
- SProcPtr = ^SProcRec;;
- SProcRec = RECORD
- nxtSrch: SProcHndl; {handle to next sProcRec}
- srchProc: ProcPtr {pointer to search procedure}
- END;
-
- Any number of search procedures can be installed in a linked list, each element of
- which will be called sequentially by the Color Manager, and given the chance to act
- or pass on the color. Since each device is a shared resource, a simple method (the
- gdID) is provided to identify the caller to the search procedures, as well as routines
- to add and delete custom procedures from the linked list.
-
- The interface is as follows:
-
- FUNCTION SearchProc (rgb: RGBColor; VAR position: LONGINT): BOOLEAN;
-
- When attempting to approximate a color, the Color Manager calls each search procedure
- in the list until the boolean value returns as TRUE. The index value of the closest
- match is returned by the position parameter. If no search procedure installed in the
- linked list returns TRUE, the Color Manager calls the default search procedure.
-
- The application can also supply a custom complement procedure to find the complement
- of a specified color. Complement procedures work the same as search procedures, and
- are kept in a list beginning in the gDevice port’s gdCompProc field.
-
- TYPE
- CProcHndl = ^CProcPtr;
- CProcPtr = ^CProcRec;
- CProcRec = RECORD
- nxtComp: CProcHandle; {pointer to next CProcRec}
- compProc: ProcPtr {pointer to complement procedure}
- END;
-
- The default complement procedure simply uses the 1’s complement of the RGB color
- components before looking them up in the inverse table. The interface is as follows:
-
- FUNCTION CompProc (VAR rgb: RGBColor) : BOOLEAN;
-
- _______________________________________________________________________________
-
- »Operations on Search and Complement Functions
-
- PROCEDURE AddSearch (searchProc: ProcPtr);
- PROCEDURE AddComp (compProc: ProcPtr);
-
- The AddSearch and AddComp routines add a procedure to the head of the current device
- record’s list of search or complement procedures. These routines allocate an SProcRec
- or CProcRec.
-
- PROCEDURE DelSearch (searchProc: ProcPtr);
- PROCEDURE DelComp (compProc: ProcPtr);
-
- The DelSearch and DelComp procedures remove a custom search or complement procedure
- from the current device record’s list of search or complement procedures. These
- routines dispose of the chain element, but do nothing to the procPtr.
-
- PROCEDURE SetClientID (id: INTEGER);
-
- The SetClientID procedure sets the gdID field in the current device record to identify
- this client program to its search and complement procedures.
-
- _______________________________________________________________________________
-
-
- æKY Summary…of…the…Color…Manager
- æC »SUMMARY OF THE COLOR MANAGER ColorManager
- _______________________________________________________________________________
-
- Constants
-
- CONST
- minSeed = 1023; {minimum seed value for ctSeed}
-
- _______________________________________________________________________________
-
- Data Types
-
- TYPE
- ITabHandle = ^ITabPtr;
- ITabPtr = ^ITab;
- ITab = RECORD
- iTabSeed: LONGINT; {copy of color table seed}
- iTabRes: INTEGER; {resolution of table}
- iTTable: ARRAY[0..0] OF SignedByte {byte color }
- { table index values}
- END;
-
- SProcHndl = ^SProcPtr;
- SProcPtr = ^SProcRec;;
- SProcRec = RECORD
- nxtSrch: SProcHndl; {handle to next sProcRec}
- srchProc: ProcPtr {pointer to search procedure}
- END;
-
- CProcHndl = ^CProcPtr;
- CProcPtr = ^CProcRec;
- CProcRec = RECORD
- nxtComp: CProcHandle; {pointer to next CProcRec}
- compProc: ProcPtr {pointer to complement procedure}
- END;
-
- ReqListRec = RECORD
- reqLSize: INTEGER; {request list size –1}
- reqLData: ARRAY [0..0] of INTEGER {request list data}
- END;
-
- _______________________________________________________________________________
-
- Routines
-
- Color Conversion
-
- FUNCTION Color2Index (VAR rgb: RGBColor): LONGINT;
- PROCEDURE Index2Color (index: LONGINT; VAR rgb: RGBColor);
- PROCEDURE InvertColor (VAR theColor: RGBColor);
- FUNCTION RealColor (color: RGBColor) : BOOLEAN;
- PROCEDURE GetSubTable (myColors: CTabHandle; iTabRes: INTEGER;
- targetTbl:CTabHandle);
- PROCEDURE MakeITable (colorTab: CTabHandle; inverseTab: ITabHandle;
- res: INTEGER);
-
- Color Table Management
-
- FUNCTION GetCTSeed: LONGINT;
- PROCEDURE ProtectEntry (index: INTEGER; protect: BOOLEAN);
- PROCEDURE ReserveEntry (index: INTEGER; reserve: BOOLEAN);
- PROCEDURE SetEntries (start, count: INTEGER; aTable: cSpecArray);
- PROCEDURE RestoreEntries (srcTable:CTabHandle;dstTable:CTabHandle;
- VAR selection:ReqListRec);
- PROCEDURE SaveEntries (srcTable:CTabHandle;resultTable:CTabHandle; VAR selection:ReqListRec)
-
- Operations on Search and Complement Functions
-
- PROCEDURE AddSearch (searchProc: ProcPtr);
- PROCEDURE AddComp (compProc: ProcPtr);
- PROCEDURE DelSearch (searchProc: ProcPtr);
- PROCEDURE DelComp (compProc: ProcPtr);
- PROCEDURE SetClientID (id: INTEGER);
-
- Error Handling
-
- FUNCTION QDError: INTEGER;
-
- _______________________________________________________________________________
-
- Assembly Language Information
-
- Constants
-
- minSeed EQU 1023 ;minimum ctSeed value
-
- ITab structure
-
- iTabSeed EQU $0 ;[long] ID of owning color table
- iTabRes EQU $4 ;[word] client ID
- iTTable EQU $6 ;table of indices starts here
- ;in this version, entries are BYTE
-
- SProcRec structure
-
- nxtSrch EQU $0 ;[pointer] link to next proc
- srchProc EQU $4 ;[pointer] pointer to routine
-
- CProcRec structure
-
- nxtComp EQU $0 ;[pointer] link to next proc
- compProc EQU $4 ;[pointer] pointer to routine
-
- Request list structure
-
- reqLSize EQU 0 ;[word] request list size –1
- reqLData EQU 2 ;[word] request list data
-
- Further Reference:
- _______________________________________________________________________________
- Color QuickDraw
- Graphics Devices
- Palette Manager
- Color Picker Package
- 32-Bit QuickDraw Documentation
-
- æKY ColorPickerPackage
- æC
- _______________________________________________________________________________
-
- COLOR PICKER PACKAGE
- _______________________________________________________________________________
-
- About…the…Color…Picker…Chapter
- About…the…Color…Picker…Package
- Color…Models
- The…RGB…Model
- The…CMYK…Model
- The…HLS…and…HSV…Models
- Color…Models…in…the…Dialog…Box
- Using…the…Color…Picker…Package
- Presenting…the…Dialog…Box
- Conversion…Facilities
- Color…Picker…Routines
- Displaying…the…Color…Picker…Dialog…Box
- Converting…Between…Color…Models
- Converting…Between…SmallFract…and…Fixed…Values
- Summary…of…the…Color…Picker…Package
- Color…Picker…Package…Constants
- Color…Picker…Package…Data…Types
- Color…Picker…Package…Routines
- Assembly…Language…Information…for…Color…Picker…Package
- _______________________________________________________________________________
-
-
-
- æKY About…the…Color…Picker…Chapter
- æC »ABOUT THIS CHAPTER Color Picker Package
- _______________________________________________________________________________
-
- This chapter describes the Color Picker Package, a utility with which
- applications can offer users a standard dialog box for choosing a color. You
- should be familiar with the material in the Graphics Overview chapter in this
- volume, especially the discussion of direct and indexed video devices. Effective
- use of the Color Picker will also require familiarity with Color QuickDraw,
- described in Volume V of Inside Macintosh, and in this volume.
-
- This chapter supersedes the description of the Color Picker in Volume V.
-
- You need to read this chapter if your application uses the color system
- introduced with Color QuickDraw (rather than the 8-color system available with
- the original QuickDraw), and you need to solicit color choices from your users.
- If your application limits user selection to a specific list of colors, you may
- need to construct your own dialog box for color selection using Palette Manager
- routines, as the Color Picker allows the user to choose colors from the entire
- range available with Color QuickDraw’s 48-bit RGB values.
-
- _______________________________________________________________________________
-
- æKY About…the…Color…Picker…Package
- æC »ABOUT THE COLOR PICKER PACKAGE Color Picker Package
- _______________________________________________________________________________
-
- The Color Picker Package provides you with a standard way of soliciting a color
- choice from the user. When an application calls the Color Picker’s GetColor
- function, the Color Picker presents its dialog box to the user, as shown in
- Figure 17-1.
-
- When the user is satisfied with a chosen color and clicks the OK button,
- GetColor returns that color to your application as an RGB value.
-
- ø 17.1 The Color Picker dialog box
-
- The Color Picker also has utility routines for converting between RGB values and
- several other color systems, and for converting between the integers Color
- QuickDraw uses for RGB colors and the SmallFract values the Color Picker uses
- with alternate color models.
-
- This chapter describes the color models the Color Picker works with, and how you
- set up and present the dialog box to users.
-
- _______________________________________________________________________________
-
- æKY Color…Models
- æC »COLOR MODELS Color Picker Package
- _______________________________________________________________________________
-
- Both QuickDraw and standard video monitors work with a red, green, blue (RGB)
- color model, but in graphic arts and design other color models, such as HLS
- (hue, lightness, saturation) or HSV (hue, saturation, value) are used, and in
- printing the CMYK (cyan, magenta, yellow, and black) model predominates. Great
- books have been written about color; this section presents a quick survey of the
- models with which the Color Picker works.
-
- _______________________________________________________________________________
-
- æKY The…RGB…Model
- æC »The RGB Model Color Picker Package
- _______________________________________________________________________________
-
- In the RGB model, the three colors are additive. The more of each color you add
- the closer the resulting color is to white. This is the way light-produced
- colors work; turning on the red, green, and blue phosphors of a television
- screen produces white, as does shining lights of red, green, and blue upon a
- stage.
-
- The QuickDraw data structure for an RGBColor record is
-
- RGBColor = RECORD
- red: Integer; {red component}
- green: Integer; {green component}
- blue: Integer {blue component}
- END;
-
- The frontispiece of Volume V of Inside Macintosh shows a color cube that
- represents the values possible in an RGB system. Figure 17-2 is a
- black-and-white representation of that cube.
-
-
-
- ø 17.2 The RGB Color Cube
-
- Starting at one corner, with zero values for each color, is black. Increasing
- any one of the values produces shades of that color, increasing its saturation.
- Increasing all three values equally generates a diagonal line across the cube
- toward full value (65,535) for each, which is white. Values on that diagonal are
- shades of gray; values off the line in any direction are colors. For example,
- pink in the RGB model would be full red with some equal amount of green and
- blue, in effect moving from the black corner of the color cube up along the edge
- to full red, then traversing a diagonal across the top face from red toward
- white.
-
-
- ø 17.3 Getting to pink
-
- _______________________________________________________________________________
-
- æKY The…CMYK…Model
- æC »The CMYK Model Color Picker Package
- _______________________________________________________________________________
-
- In the CMYK model, which is used by the print world, the three colors and black
- are subtractive: increasing values moves the result closer to black. This is
- intuitive for printing, which is usually done on white paper—to get white, don’t
- print anything. In theory, black could be achieved by mixing full values of
- cyan, magenta, and yellow, but purity in chemicals is more problematic than with
- light, and four-color print processes use black as well. The Color Picker’s
- CMYColor data structure defines only the three colors. It uses SmallFract
- values, which are the fractional part of Fixed values, as described in Color
- Picker Conversion Facilities.
-
- CMYColor = RECORD
- cyan: SmallFract;
- magenta: SmallFract;
- yellow: SmallFract
- END;
-
- Note that cyan, magenta, and yellow are complements of red, green, and blue.
-
- ø 17.4 CMY on the color cube
-
- _______________________________________________________________________________
-
- æKY The…HLS…and…HSV…Models
- æC »The HLS and HSV Models Color Picker Package
- _______________________________________________________________________________
-
- The components of the HLS and HSV models are not three diverse colors, as in RGB
- and CMY. The HLS and HSV models separate color, or hue, from brightness and
- saturation.
-
- Brightness is a measure of how much black is in a color, saturation is a measure
- of how much white it contains. Hue is indicated by an arbitrary assignment of
- numbers to colors. The amount of that hue is indicated by a saturation value,
- and the brightness of the color is a third value. The best representation for
- such a system is an inverted cone, in which hues vary around the perimeter,
- where they are most highly saturated, and brightness increases from the tip of
- the cone to the disk. The gray line from black to white begins at the bottom-tip
- and runs up through the cone to the center of the disk.
-
- ø 17.5 The HLS/HSV color cone
-
- This is the model portrayed in the Color Picker’s dialog box. The disk is shown
- full face, the hues are at their most saturated around the rim, and the
- brightness line down the cone is controlled by the scroll bar.
-
- In the Color Picker’s color wheel the value for pure red is 0, pure green is
- 21,845, and pure blue is 43,690. The amount of black is set by the value for
- brightness (meaning lightness in HLS, value in HSV), and the amount of color in
- the mix is set by saturation. Pink in the HLS or HSV system would be obtained by
- setting hue to red, saturation to some amount less than full, and brightness to
- full.
-
- The HLS and HSV systems are sufficiently similar that the Color Picker can treat
- them as one by a simple expedient: the HLS model is treated by the Picker as if
- it were ordered HSL; this puts hue and saturation in the same relative positions
- in the data structures of both models.
-
- HSVColor = RECORD
- hue: SmallFract; {fraction of circle, red at 0}
- saturation: SmallFract; {0-1, 0 is gray, 1 is pure color}
- value: SmallFract {0-1, 0 is black, 1 is max intensity}
- END;
-
- HSLColor = RECORD
- hue: SmallFract; {fraction of circle, red at 0}
- saturation: SmallFract; {0-1, 0 is gray, 1 is pure color}
- lightness: SmallFract {0-1, 0 is black, 1 is white}
- END;
- _______________________________________________________________________________
-
- æKY Color…Models…in…the…Dialog…Box
- æC »Color Models in the Dialog Box Color Picker Package
- _______________________________________________________________________________
-
- The controls in the dialog box are designed for use in the HSL or HSV models:
- hue is chosen by moving the cursor around the color wheel, saturation by moving
- in or out from the center, and brightness (value or lightness) is specified by
- the scroll bar at the right. The way RGB values vary in response to the dialog
- controls is not intuitive, but it can be instructive on how the models relate.
-
- The dialog box cannot exactly match the print world’s additive effect, and it
- does not offer CMYK controls, but routines for converting between RGB and CMY
- (cyan, magenta, yellow, without a black component) are included in the Color
- Picker Package.
-
- _______________________________________________________________________________
-
- æKY Using…the…Color…Picker…Package
- æC »USING THE COLOR PICKER PACKAGE Color Picker Package
- _______________________________________________________________________________
-
- Most developers will only use the Color Picker Package to display the Color
- Picker’s dialog box. A few developers may need to use the color model and
- SmallFract conversion routines.
-
- _______________________________________________________________________________
-
- æKY Presenting…the…Dialog…Box
- æC »Presenting the Dialog Box Color Picker Package
- _______________________________________________________________________________
-
- Your program can present a user with the Color Picker dialog box, shown in
- Figure 1, by calling the Color Picker’s GetColor function.
-
- When called by an application, the Color Picker displays the dialog box,
- including prompt text, which appears in the upper-left corner, and the initial
- color, which appears in the lower of the two rectangles below the prompt. The
- color being picked, in the upper rectangle, ranges over the entire color space
- in response to the controls in the rest of the dialog box. Your application can
- supply the prompt text, an initial color, the location of the upper-left corner
- of the dialog box window, and whether it should appear on the main or deepest
- screen.
-
- The two groups of numeric fields (Hue/Saturation/Brightness and Red/Green/Blue)
- show the parameters of the color being picked in the two color systems. The user
- may increase or decrease the values using the arrow controls or enter values
- directly into any of the six fields.
-
- The range for all of the component values is 0 to 65,535. Larger values are
- clipped to 65,535 after the user exits the field. When the user is increasing or
- decreasing the hue using the arrow controls, 0 wraps around to 65,535, so the
- user can circumnavigate the wheel with arrow controls just as with the cursor.
- The hue value for pure red is 0; pure green is 21,845; pure blue is 43,690.
-
- The user may select a single RGB value from Color QuickDraw’s entire range of
- 248 color values.
-
- On black-and-white hardware (or in less than 4-bit mode), the display appears in
- black and white; the Color Picker returns the RGB value selected, but does not
- call any color routines in the course of responding to user actions.
-
- On devices with a variable CLUT, the Color Picker temporarily borrows a color
- table entry to display the exact color in the rectangle that shows the color
- currently being picked. (As a result, when your application subsequently
- displays the user’s chosen color, if you let the Color Manager approximate the
- user’s value the result will probably differ somewhat from the one picked.) The
- Color Picker restores the color environment when it is done.
-
- _______________________________________________________________________________
-
- æKY Conversion…Facilities
- æC »Conversion Facilities Color Picker Package
- _______________________________________________________________________________
-
- In addition to the GetColor function that puts up the Color Picker dialog box,
- the Color Picker provides six procedures for converting between RGB and the CMY,
- HLS, and HSV color systems; and two functions that convert between SmallFract
- and fixed numbers. Most developers will use only the GetColor function.
-
- The CMY, HSL, and HSV structures are defined by ColorPicker with SmallFract
- values rather than INTEGER values (as used in RGBColor). A SmallFract value is
- the fractional part of a Fixed number, which is the low-order word. The Integer
- values in RGBColor are actually used as unsigned integer-sized values; by using
- SmallFract values, the ColorPicker avoids sign extension problems in the
- conversion math. The Color Picker provides two functions for converting between
- SmallFract and fixed numbers. Most developers will not need to use these
- facilities.
-
- _______________________________________________________________________________
-
- æKY Color…Picker…Routines
- æC »COLOR PICKER ROUTINES Color Picker Package
- _______________________________________________________________________________
-
- The following cards describe the Color Picker routines.
- _______________________________________________________________________________
-
- æKY Displaying…the…Color…Picker…Dialog…Box
- æC »Displaying the Color Picker Dialog Box Color Picker Package
- _______________________________________________________________________________
-
- FUNCTION GetColor (where: Point; prompt: Str255; inColor: RGBColor; VAR
-
- outColor: RGBColor) : BOOLEAN;
-
- The GetColor function displays the Color Picker dialog box on the screen, with
- its upper-left corner located at the point you designate with the where
- parameter. The Color Picker Package will display the dialog box and accept color
- selection on any screen, not just the main screen. If where = (0,0), the dialog
- box is positioned neatly on the main screen—centered horizontally and with
- one-third of the empty space above the box and two-thirds below, whatever the
- screen size. If an application supplies a where parameter of -1,-1, the Color
- Picker will center the dialog box on what the Color Picker determines to be the
- best screen, maximizing for depth and color.
-
- The prompt string is displayed in the upper-left corner of the dialog box. The
- inColor parameter is the starting color, which the user may want for comparison;
- it is displayed immediately below the current output color (the one the user is
- picking). The OutColor parameter is set to the last color value the user picks,
- if and only if the user clicks OK. On entry, it is treated as undefined, so the
- output color sample originally matches the input. Although the color being
- picked may vary widely, the input color sample remains fixed, and clicking in
- the input sample resets the output color sample to match it.
-
- GetColor returns TRUE if the user exits by clicking the OK button or FALSE if
- the user cancels.
-
- _______________________________________________________________________________
-
- æKY Converting…Between…Color…Models
- æC »Converting Between Color Models Color Picker Package
- _______________________________________________________________________________
-
- These six routines offer conversions between RGB on the one hand and CMY, HSV,
- or HSL on the other.
-
- PROCEDURE CMY2RGB (cColor: CMYColor; VAR rColor: RGBColor);
-
- The CMY2RGB procedure converts a CMYColor record to an RGBColor record.
-
- PROCEDURE HSL2RGB (hColor: HSLColor; VAR rColor: RGBColor);
-
- The HSL2RGB procedure converts an HSLColor record to an RGBcolor record.
-
- PROCEDURE HSV2RGB (hColor: HSVColor; VAR rColor: RGBColor);
-
- The HSV2RGB procedure converts an HSVColor record to an RGBColor record.
-
- PROCEDURE RGB2CMY (rColor: RGBColor; VAR cColor: CMYColor);
-
- The RGB2CMY procedure converts an RGBColor record to a CMYColor record.
-
- PROCEDURE RGB2HSL (rColor: RGBColor; VAR hColor: HSLColor);
-
- The RGB2HSL procedure converts an RGBColor record to an HSLColor record.
-
- PROCEDURE RGB2HSV (rColor: RGBColor; VAR hColor: HSVColor);
-
- The RGB2HSV procedure converts an RGBColor record to an HSVColor record.
-
- _______________________________________________________________________________
-
- æKY Converting…Between…SmallFract…and…Fixed…Values
- æC »Converting Between SmallFract and Fixed Values Color Picker Package
- _______________________________________________________________________________
-
- A SmallFract value can represent a value between 0 and 65,535. They can be
- assigned directly to and from Integers.
-
- FUNCTION SmallFract2Fix(s: SmallFract): Fixed;
-
- The SmallFract2Fix function converts a SmallFract value to a fixed integer.
-
- FUNCTION Fix2SmallFract(f: Fixed): SmallFract;
-
- The Fix2SmallFract function converts a fixed integer to a SmallFract value.
- _______________________________________________________________________________
-
- æKY Summary…of…the…Color…Picker…Package
- æC »SUMMARY OF THE COLOR PICKER PACKAGE Color Picker Package
- _______________________________________________________________________________
-
- The following cards summarize the constants, data types, and routines for the
- Color Picker Package.
- _______________________________________________________________________________
-
- æKY Color…Picker…Package…Constants
- æC »Constants Color Picker Package
- _______________________________________________________________________________
-
- CONST
-
- MaxSmallFract = $0000FFFF; {maximum SmallFract value, as LONGINT}
- _______________________________________________________________________________
-
- æKY Color…Picker…Package…Data…Types
- æC »Data Types Color Picker Package
- _______________________________________________________________________________
-
- TYPE
- SmallFract = INTEGER; {unsigned fraction between 0 and 1}
- HSVColor = RECORD
- hue: SmallFract; {fraction of circle, red at 0}
- saturation: SmallFract; {0-1, 0 is gray, 1 is pure color}
- value: SmallFract {0-1, 0 is black, 1 is max intensity}
- END;
-
- HSLColor = RECORD
- hue: SmallFract; {fraction of circle, red at 0}
- saturation: SmallFract; {0-1, 0 is gray, 1 is pure color}
- lightness: SmallFract {0-1, 0 is black, 1 is white}
- END;
-
- CMYColor = RECORD {CMY and RGB are complements}
- cyan: SmallFract;
- magenta: SmallFract;
- yellow: SmallFract
- END;
- _______________________________________________________________________________
-
- æKY Color…Picker…Package…Routines
- æC »Routines Color Picker Package
- _______________________________________________________________________________
-
- Displaying the Dialog Box
-
- FUNCTION GetColor (where: Point; prompt: Str255; inColor: RGBColor; VAR
- outColor: RGBColor) : BOOLEAN;
-
- Converting Between Color Models
-
- PROCEDURE CMY2RGB (cColor: CMYColor; VAR rColor: RGBColor);
- PROCEDURE HSL2RGB (hColor: HSLColor; VAR rColor: RGBColor);
- PROCEDURE HSV2RGB (hColor: HSVColor; VAR rColor: RGBColor);
- PROCEDURE RGB2CMY (rColor: RGBColor; VAR cColor: CMYColor);
- PROCEDURE RGB2HSL (rColor: RGBColor; VAR hColor: HSLColor);
- PROCEDURE RGB2HSV (rColor: RGBColor; VAR hColor: HSVColor);
-
- Converting Between SmallFract and Fixed Values
-
- FUNCTION SmallFract2Fix (s: SmallFract): Fixed;
- FUNCTION Fix2SmallFract (f: Fixed): SmallFract;
- _______________________________________________________________________________
-
- æKY Assembly…Language…Information…for…Color…Picker…Package
- æC »Assembly Language Information Color Picker Package
- _______________________________________________________________________________
-
- Constants
-
- Fix2SmallFract .EQU 1 ; selector for Fix2SmallFract
- SmallFract2Fix .EQU 2 ; selector for mallFract2Fix
- CMY2RGB .EQU 3 ; selector for CMY2RGB
- RGB2CMY .EQU 4 ; selector for RGB2CMY
- HSL2RGB .EQU 5 ; selector for HSL2RGB
- RGB2HSL .EQU 6 ; selector for RGB2HSL
- HSV2RGB .EQU 7 ; selector for HSV2RGB
- RGB2HSV .EQU 8 ; selector for RGB2HSV
- GetColor .EQU 9 ; selector for GetColor
-
- Macro
- _Pack12
- _______________________________________________________________________________
-
-
- æKY ColorQuickDraw
- æC
- _______________________________________________________________________________
-
- COLOR QUICKDRAW
- _______________________________________________________________________________
-
- About…The…Color…Quickdraw…Chapter
- About…Color…Quickdraw
- Direct…Colors
- PixMap…Record…Extensions
- Direct…Pixel…Examples
- PICT…Extensions
- Well-Behaved…Graphics…Applications
- Using…Color…Quickdraw
- Copying…PixMap…Records
- Dithering
- Resizing…Images
- Luminance…Mapping
- Image…Resolution
- Importing…PixMap…Records
- Exporting…PixMap…Records
- Converting…a…Bitmap…to…a…Region
- Checking…that…QuickDraw…is…Done
- New…Color…Quickdraw…Routines
- New…QuickDraw…Result…Codes
- Creating…an…Extended…PICT2…Picture
- From…Bitmap…to…Region
- Drawing…Completion
- Reporting…Data…Structure…Changes
- The…Extended…PICT2…Format
- Sample…Extended…PICT2…File
- PICT2…Opcode…Types
- Extended…PICT2…Opcodes
- Summary…of…Color…Quickdraw…Changes
- Color…Quickdraw…Constants
- Color…Quickdraw…Data…Types
- Color…Quickdraw…Routines
- Color…Quickdraw…Result…Codes
- _______________________________________________________________________________
-
-
-
- æKY About…The…Color…Quickdraw…Chapter
- æC »ABOUT THIS CHAPTER Color QuickDraw
- _______________________________________________________________________________
-
- This chapter describes extensions to Color QuickDraw. You should be familiar
- with the Graphics Overview in this volume, and with the Color QuickDraw
- description in Inside Macintosh, Volume V. Developers of graphics cards and
- drivers should also be familiar with the Slot Manager, Graphics Devices Manager,
- and the Control Panel as described in both Inside Macintosh and and Developing
- Cards and Drivers for the Macintosh Family, second edition.
-
- This chapter describes extensions to the color facilities of Color QuickDraw,
- and other new features, notably luminance mapping techniques and routines by
- which existing applications can signal QuickDraw that a data structure has been
- modified directly, rather than by use of QuickDraw routines.
-
- If you use offscreen graphics to prepare images before copying them to the
- screen, read the Graphics Devices Manager chapter in this volume for a
- description of new routines that considerably reduce the complexity of that
- task.
- _______________________________________________________________________________
-
- æKY About…Color…Quickdraw
- æC »ABOUT COLOR QUICKDRAW Color QuickDraw
- _______________________________________________________________________________
-
- Color QuickDraw now supports images that use direct, as well as indexed,
- specification of colors.
-
- Although an application specifies a color in terms of RGB space, the actual
- value Color QuickDraw sends to the graphics card frame buffer (video RAM) is an
- index value, which is used as input to the CLUT. An 8-bit index can specify 256
- different entries (2 to the 8th power). On CLUT devices, the relationship
- between the index value and the color generated depends on what colors are
- currently stored where in the table.
-
- At the cost of larger RAM requirements and, in some situations, slower
- performance, direct color specification eliminates the need for table look-ups
- and color searching algorithms, and lets your application directly specify over
- 16 million colors. (For a comparison of the differences between indexed and
- direct colors, see the Graphics Overview chapter.)
-
- In addition to direct color, Color QuickDraw now also provides
-
- • support for a true gray-scale display, providing better image fidelity on
- gray-scale devices
-
- • a routine that converts a BitMap record into a region, which means you
- can, in effect, use region-manipulating routines on BitMap records
-
- • four routines that enable you to signal Color QuickDraw when your
- application directly modifies a CLUT, PixPat, GrafPort, or GDevice data
- structure. (Direct modification is still discouraged.)
-
- • a routine that creates and retrieves pictures with variable dots per inch
- resolution
- _______________________________________________________________________________
-
- æKY Direct…Colors
- æC »DIRECT COLORS Color QuickDraw
- _______________________________________________________________________________
-
- Color QuickDraw now supports pixmaps with direct color specification as well as
- the indexed method supported by the original release of Color QuickDraw. Since
- QuickDraw has always striven to be device-independent, many applications need
- make no changes. If your application specifies RGB colors, the system determines
- the best colors for indexed devices and passes your RGB color to direct devices.
-
- Changes to the Color QuickDraw interface affect only these two
- color-specification data structures:
-
- • the PixMap data structure that describes an image
-
- • the PICT2 format in which images and graphics drawing operations are
- stored
-
- Extensions to these two structures are described next.
- _______________________________________________________________________________
-
- æKY PixMap…Record…Extensions
- æC »PixMap Record Extensions Color QuickDraw
- _______________________________________________________________________________
-
- Color QuickDraw supports two new pixel formats, corresponding to 16-bit and
- 32-bit pixel depths. In both cases, the pixel’s displayed color is specified by
- the pixel value; the pixel value is not an index into a CLUT.
-
- Note that the format of a PixMap record is not changed from that introduced with
- the Macintosh II, but six PixMap fields can have new values. The PixMap data
- structure is shown here, only the fields that can have new values are discussed.
- See the Color QuickDraw chapter in Volume V for a complete PixMap description.
-
- PixMap = RECORD
- baseAddr: Ptr; {pointer to PixMap data}
- rowBytes: Integer; {offset to next row}
- bounds: Rect; {boundary rectangle}
- pmVersion: Integer; {Color QuickDraw flags}
- packType: Integer; {packing format}
- packSize: Longint; {size of data in packed state}
- hRes: Fixed; {horizontal resolution}
- vRes: Fixed; {vertical resolution}
- pixelType: Integer; {format of pixel image}
- pixelSize: Integer; {physical bits per pixel}
- cmpCount: Integer; {logical components per pixel}
- cmpSize: Integer; {logical bits per component}
- planeBytes: Longint; {offset to next plane}
- pmTable: CTabHandle; {absolute colors for this image}
- pmReserved: Longint {reserved for future expansion}
- END;
-
- Direct fields
-
- rowBytes: The restriction that rowbytes be less than $2000 has been relaxed:
- rowbytes must be less than $4000. RowBytes must be even, and for best
- performance it should be a multiple of 4.
-
- pmVersion: Normally 0. If pmVersion is 4, Color QuickDraw treats the pixmap’s
- baseAddr as being 32-bit clean. This flag can be set by a new Graphics Devices
- Manager routine, SetPMVersion. Most applications never need to set this field;
- it is for low-level driver support.
-
- pixelType: Direct pixel values are specified by a pixelType field value of
- RGBDirect, or 16. In a PixMap record of the gDevice record for a direct device,
- the pixelType field will be set to the constant RGBDirect when the screen depth
- is set.
-
- pixelSize: Pixel sizes must be a power of two. Color QuickDraw supports pixel
- sizes of 1, 2, 4, and 8 bits; Color QuickDraw adds pixel sizes of 16 and 32
- bits.
- cmpCount
-
- cmpCount: With indexed pixels, each pixel is a single value representing an
- index into a color table, and therefore the cmpCount field of a PixMap record is
- 1—the index is the single component. With direct pixels, each pixel contains
- three components, one integer each for the intensities of red, green, and blue,
- and cmpCount is 3. Other values are undefined.
-
- cmpSize: The cmpSize field specifies the size of each component. A 32-bit pixel
- consists of three components (red, green, and blue values) of 8 bits each. Since
- cmpCount * cmpSize (3 * 8 = 24) is less than the value of pixelSize, 8 bits in
- the pixel are not part of any component. These bits are unused: Color QuickDraw
- sets them to zero in any image it creates, and if presented with a 32-bit image,
- for example in CopyBits, it passes whatever bits are there. (Generally,
- therefore, your application should clear image memory to 0 before creating a
- 32-bit image.)
-
- A 16-bit pixel consists of three components of 5 bits each. This leaves an
- unused high-order bit, which QuickDraw sets to 0.
-
- Color QuickDraw expects that the sizes of all components are the same, and that
- cmpCount * cmpSize is less than or equal to pixelSize.
-
- In each direct pixel, the pixel value is the concatenation of the red, green,
- and blue components, where red is in the most significant bits and blue is in
- the least significant. The entire direct pixel is right justified; unused bits
- occupy the highest-order bits.
- _______________________________________________________________________________
-
- æKY Direct…Pixel…Examples
- æC »Direct Pixel Examples Color QuickDraw
- _______________________________________________________________________________
-
- Figure 16-1 shows a 32-bit direct pixel value, in which the pixel and component
- fields have been set up as
-
- pixelType = 16; {RGBDirect}
- pixelSize = 32; {must be a power of 2}
- cmpCount = 3; {red, green, and blue values}
- cmpSize = 8; {8 bits for each component}
-
- ø 16.1 A 32-bit direct pixel
-
- In this example, the pixel value (hexadecimal) is $00178609, which deconstructs
- into component values of $17 red, $86 green, and $09 blue, resulting in a medium
- green. Figure 16-2 approximates the same color as in Figure 16-1 using a 16-bit
- pixel specified as follows:
-
- pixelType = 16; {RGBDirect}
- pixelSize = 16; {Must be a power of 2}
- cmpCount = 3; {red, green, and blue values}
- cmpSize = 5; {5 bits for each component}
-
- ø 16.2 A 16-bit direct pixel
-
- Here the pixel value is $0A01, with component values of $02, $10, and $01 for
- red, green and blue.
-
- When converting a 32-bit pixel value to 16 bits, the three least significant
- bits are dropped for each component. When converting a 16-bit pixel value to 32
- bits, the most significant three bits of each component are replicated and added
- to constitute the least significant three bits of the resulting 8-bit component,
- as illustrated in Figure 16-3.
-
- ø 16.3 Converting a 16-bit direct pixel to 32-bit direct
-
- In this way, white stays white, black stays black, and other values are spread
- appropriately.
-
- Figures 16-4 to 16-9 show first how Color QuickDraw converts a full 48-bit RGB
- color to 32, 16, and 8 bit values (the latter indexed), and then the reverse
- process, of converting those values back to 48 bits.
-
- ø 16.4 Converting a 48-bit RGB value to 32-bit direct
-
- A 32-bit direct pixel uses the most significant 8 bits of each component, and
- has an 8-bit pad.
-
- ø 16.5 Converting a 48-bit RGB value to 16-bit direct
-
- A 16-bit direct pixel uses the most significant 5 bits of each component, and
- has a 1-bit pad.
-
- ø 16.6 Converting a 48-bit value to an 8 bit index
-
- To obtain an 8-bit pixel value, the Color Manager determines the closest RGB
- value in the CLUT; its index value is stored in the 8-bit pixel. In the standard
- 8-bit CLUT, from 'CLUT' resource with ID of 8, the nearest value to the original
- RGB value of Figure 16-4 is in table entry 161. Note that with indexed pixels,
- the pixel value has no direct relation to the original RGB value.
-
- ø 16.7 Converting an 32-bit pixel to 48 bits
-
- Color QuickDraw expands a 32-bit pixel into a 48-bit value by dropping the pad
- byte and doubling each 8-bit component. Note that the resulting 48-bit value
- differs (in the least significant 8 bits of each component) from the original in
- Figure 16-4.
-
- ø 16.8 Converting an 16-bit pixel to 48 bits
-
- Color QuickDraw expands a 16-bit pixel into a 48-bit value by dropping the pad
- bit and inserting three copies of each 5-bit component and a copy of the most
- significant bit into each 16-bit component of the destination. Note that the
- result differs (in the least significant 11 bits of each component) from the
- original value.
-
- ø 16.9 Converting an 8-bit indexed pixel to 48 bits
-
- Color QuickDraw expands an 8-bit indexed pixel into a 48-bit value by taking the
- 48-bit value pointed to in the CLUT. The difference between this value and the
- original 48-bit value varies, depending on the CLUT values.
-
- _______________________________________________________________________________
-
- æKY PICT…Extensions
- æC »PICT Extensions Color QuickDraw
- _______________________________________________________________________________
-
- The PICT2 picture format defined for Color QuickDraw only supports images
- consisting of CLUT indices. The PICT2 format has been expanded so that it can
- record images with pixels that directly specify a given color.
-
- To the current imaging opcodes BitsRect, BitsRgn, PackBitsRect, and PackBitsRgn,
- Color QuickDraw adds DirectBitsRect and DirectBitsRgn. These opcodes enable your
- application to cut, paste, and store images with up to 32 bits of color
- information per pixel.
-
- A new routine, the OpenCPicture function, lets your application create a PICT2
- file and pass rectangle and resolution information, which is stored in the PICT2
- header. This provides a simple mechanism for creating images with spatial
- resolution other than 72 dpi. The OpenCPicture function is described in “New
- Color QuickDraw Routines” later in this chapter.
-
- The following opcodes occur only in pictures using the extended PICT2 format.
- Two new opcodes specify direct pixels:
-
- DirectBitsRect EQU $9A ; direct data copybits, rect clipped
- DirectBitsRgn EQU $9B ; direct data copybits, rgn clipped
-
- In addition, an opcode has been defined to specify font information:
-
- FontName EQU $2C ; font ID and name
-
- The PICT2 format is described fully in “The Extended PICT2 Format.”
- _______________________________________________________________________________
-
- æKY Well-Behaved…Graphics…Applications
- æC »WELL-BEHAVED GRAPHICS APPLICATIONS Color QuickDraw
- _______________________________________________________________________________
-
- Over the years, some developers have written applications that modify the
- QuickDraw data structures directly rather than using the routines provided for
- that purpose. Then, when Apple engineers improve QuickDraw, the applications
- break.
-
- As both QuickDraw and graphics applications grow more complex, the problem
- becomes acute. This section points to new routines you can use to signal
- QuickDraw when your application modifies certain data structures directly so
- that QuickDraw can take note and act accordingly.
-
- Applications should not directly change fields in QuickDraw data structures, but
- use the following procedures instead:
-
-
- AddComp AddSearch BackColor
- BackPat BackPixPat CharExtra
- ClipRect ColorBit CopyPixPat
- DelComp DelSearch ForeColor
- GrafDevice HideCursor HidePen
- HiliteColor MakeRGBPat Move
- MovePortTo MoveTo ObscureCursor
- OpColor PenMode PenNormal
- PenPat PenPixPat PenSize
- PortSize RGBBackColor RGBForeColor
- SetCCursor SetClientID SetClip
- SetCursor SetDeviceAttribute SetGDevice
- SetOrigin SetPenState SetPort
- SetPortBits SetPortPix ShowCursor
- ShowPen SpaceExtra TextFace
- TextFont TextMode TextSize
-
- Using these routines rather than directly modifying the data structures ensures
- that your application will fully benefit from any future improvements to
- QuickDraw. In particular, the OffscreenGWorld routines described in the Graphics
- Devices Manager chapter of this volume remove much of the need for directly
- modifying graphics data structures.
-
- Apple strongly recommends that new applications follow these guidelines.
- However, it is possible to make existing applications better-behaved by calling
- one of the following procedures after directly changing a QuickDraw data
- structure and before making any other QuickDraw call:
-
- CTabChanged
- PixPatChanged
- PortChanged
- GDeviceChanged
-
- These routines inform QuickDraw that a direct modification has occurred so it
- can update its world. They are described in the “New Color QuickDraw
- Routines”section.
-
- _______________________________________________________________________________
-
- æKY Using…Color…Quickdraw
- æC »USING COLOR QUICKDRAW Color QuickDraw
- _______________________________________________________________________________
-
- If your application uses color in straightforward ways it will probably execute
- without change in a direct pixel environment.
-
- For most other applications, the main concern is in the creation and use of
- special-purpose PixMap and GDevice records—and by using the OffscreenGWorld
- routines described in the Graphics Devices Manager chapter you will find such
- tasks far easier than before.
-
- If you must work with GrafPort, PixMap, and GDevice records in ways beyond the
- scope of the OffscreenGWorld routines, the following guidelines may aid you in
- adapting to Color QuickDraw’s direct pixel environment:
-
- • Don’t draw directly to the screen. A screen baseAddr is only guaranteed
- to be a valid pointer in 32-bit addressing mode.
-
- • Don’t directly change the fgColor or bkColor fields of a grafPort and
- expect them to be used as the pixel values. Color QuickDraw recalculates
- these values for each device. If you really want to draw in an index
- instead of a color, use a palette with pmExplicit colors, as described in
- the Palette Manager chapter in this volume. For device independant colors
- use the RGBForeColor and RGBBackColor procedures.
-
- • Fill out all the fields in a new PixMap record. The NewPixMap function
- returns a PixMap record that has been cloned from TheGDevice record’s
- PixMap record. If you don’t want a copy of the main screen’s PixMap
- record—for example, you want one that is a different depth—then you must
- fill out more fields than just pixelSize: you must fill out the
- pixelType, cmpCount, and cmpSize fields. Set pmVersion to 0 when
- initializing your own PixMap record. For future compatibility you should
- also set packType, packSize, planeBytes, and pmReserved to 0.
-
- • Don’t clone a graphic device record’s PixMap record. Instead, use the
- NewPixmap function or the CopyPixMap procedure. If you must create or
- manually clone a PixMap record, make sure to set the pmVersion field and
- other unused fields to 0 for future compatibility.
-
- • Fill out all the fields of a new GDevice. When creating an offscreen
- graphic device record by calling NewGDevice with a mode of -1, you must
- fill out the fields of the graphic device record (for instance, gdType)
- yourself. If you want a copy of an existing graphic device record, then
- copy the gdType field from it. If you explicitly want an indexed device
- then, set gdType to 0.
- • Don’t assume a PixMap record has a CLUT. Direct PixMap records need not
- have CLUTs. For compatibility, direct PixMap records should have dummy
- pmTable handles that point to color table headers with seed values equal
- to cmpSize * cmpCnt, and the ctSize field should be set to 0.
-
- Again, all these problems are eased if you use the OffscreenGWorld routines.
-
- _______________________________________________________________________________
-
- æKY Copying…PixMap…Records
- æC »Copying PixMap Records Color QuickDraw
- _______________________________________________________________________________
-
- PixMap records are copied using the current GDevice record (pointed to by the
- TheGDevice global variable) to determine the destination color information.
- Consequently, whenever copying to an offscreen PixMap record with
- characteristics differing from those of the current GDevice record (which is
- usually the main screen), you should create an appropriate offscreen graphic
- device record and set it as the current graphic device record before the copy.
- If an offscreen PixMap record is only copied from, then no offscreen graphic
- device record is needed since Color QuickDraw obtains the source color
- information from the source PixMap record. (See the Graphic Devices Manager
- chapter for information about offscreen graphics routines and data structures.)
- _______________________________________________________________________________
-
- æKY Dithering
- æC »Dithering Color QuickDraw
- _______________________________________________________________________________
-
- The CopyBits procedure now provides a new dither copy mode.
-
- Copying using CopyBits from any PixMap record to an indexed device works in one
- of two ways:
-
- • If the transfer mode is DitherCopy, then CopyBits does its best to
- provide error diffusion during the copy operation. As with arithmetic
- transfer modes, hidden colors are ignored, so that color matching is
- limited by the resolution of the inverse table for the destination
- graphics device. (See the discussion of hidden colors in the Inverse
- Table section of the Color Manager chapter, Inside Macintosh, Volume V.)
- DitherCopy provides good results for most images, but does have
- drawbacks. A clipped DitherCopy does not provide pixel-for-pixel
- equivalence to the same unclipped DitherCopy—thus updates are not
- equivalent to saving the bits behind, and clipped XOR copies will not
- perform as erases.
-
- Currently, if a color search procedure is present, copy mode is used
-
- instead of dither mode. (This may change in future versions.)
-
- • If you copy from any PixMap record to an indexed device using the classic
- copy mode, color mapping is done on a pixel-by-pixel basis—no errors are
- accumulated and hidden colors are ignored. If a color search procedure is
- present, it is called on a pixel-by-pixel basis.
-
- If you copy from any PixMap record to a direct device, dithering is never done,
- since dithering is generally useful only when copying to a destination with a
- lower color resolution than the source. If the destination device is 16-bits or
- 32-bits per pixel, then no error diffusion is performed. You can use dithering
- when copying between indexed PixMap records, such as from an 8-bit pixel depth
- to a 4-bit depth, or between two 8-bit PixMap records with different color
- tables.
-
- _______________________________________________________________________________
-
- æKY Resizing…Images
- æC »Resizing Images Color QuickDraw
- _______________________________________________________________________________
-
- When copying from direct pixel maps, if the destination rectangle is smaller
- than the source rectangle, Color QuickDraw uses an averaging technique to
- provide destination pixels, maintaining high-quality images when shrinking.
- Pixel averaging is also performed when shrinking indexed images using dither
- copy modes, regardless of the destination.
-
- _______________________________________________________________________________
-
- æKY Luminance…Mapping
- æC »Luminance Mapping Color QuickDraw
- _______________________________________________________________________________
-
- When the user sets a screen device to a gray-scale mode, Color QuickDraw places
- an evenly spaced set of grays in the device CLUT such that they form a linear
- ramp from white to black.
-
- When Color QuickDraw displays a color on a graphics device whose pmTable
- contains only grays (ignoring entries used for animation), it computes the
- luminance of the desired color and uses that to determine the appropriate gray
- value to draw.
-
- To facilitate the creation of grayscale devices, the GetCTable function has been
- enhanced to recognize additional standard CLUT IDs. As described in Volume V,
- the GetCTable function looks like this:
-
- FUNCTION GetCTable (ctID: Integer) : CTabHandle;
-
- The default grayscale CLUT for a given pixel depth can be obtained by calling
- GetCTable with a ctID value of PixelSize +32.
-
- PixelSize CLUT ID Color Table Composition
- 2 34 black, white, 33% gray, 66% gray
- 4 36 black, 14 shades of gray, white
- 8 40 black, 254 shades of gray, white
-
- The equivalent default color tables can be obtained by adding 64 to the bit
- depth, as described in the Palette Manager chapter.
-
- PixelSize CLUT ID Color Table Composition
- 2 66 black, white, 50% gray, highlight
- 4 68 black, 14 colors including a highlight, white
- 8 72 black, 254 colors including a highlight, white
- _______________________________________________________________________________
-
- æKY Image…Resolution
- æC »Image Resolution Color QuickDraw
- _______________________________________________________________________________
-
- Color QuickDraw supports pixel maps of resolutions other than 72 dots per inch
- (dpi). In the past, applications have accepted pixel maps of a certain number of
- rows and columns and assumed that they were generated on a 72 dpi device. Such
- pixel maps were usually copied and printed at a 72 dpi resolution, lending the
- impression that QuickDraw could not handle pixel maps of higher density.
-
- With the advent of frame grabbers and scanners, many pixel maps have resolutions
- of 150, 200, 300 dpi, or greater. A user expects pixel maps to display an
- approximation of the information on a 72 dpi display but print on a higher
- resolution device to the best of the device's ability.
-
- _______________________________________________________________________________
-
- æKY Importing…PixMap…Records
- æC »Importing PixMap Records Color QuickDraw
- _______________________________________________________________________________
-
- The resolution of a PixMap record is contained in the hRes and vRes fields.
- These values are fixed point numbers in dots per inch. When importing pictures,
- applications should check the picture type to see if it was created with
- OpenCPicture.
-
- An alternative is to replace the StdBits bottleneck during playback. When the
- bottleneck procedure is called, you should
-
- 1. check to guarantee that the source is a PixMap record by checking the high
- bit of the PMVersion(rowBytes) field
-
- 2. read the hRes and vRes information out of the source PixMap record
-
- At this point, the source rect field indicates the size of the source in pixels
- at the resolution specified by the hRes and vRes fields. To display it at
- another resolution, your application should compute the dest rect field value
- appropriately. For example if the source resolution is 300 dpi and the intention
- is to display it at 75 dpi, then the destination rectangle width and height
- should be computed as 1/4 of that of the source.
- _______________________________________________________________________________
-
- æKY Exporting…PixMap…Records
- æC »Exporting PixMap Records Color QuickDraw
- _______________________________________________________________________________
-
- When exporting PixMap records, your application should ensure that the hRes and
- vRes fields accurately reflect the image data. During picture recording, the
- destination rectangle of the CopyBits call should be appropriate for display at
- 72 dpi. If you want an entire picture to be a different resolution, use the
- OpenCPicture function.
-
- _______________________________________________________________________________
-
- æKY Converting…a…Bitmap…to…a…Region
- æC »Converting a Bitmap to a Region Color QuickDraw
- _______________________________________________________________________________
-
- A new function, BitMapToRegion, converts a bitmap to a region. If you used the
- PaintRgn procedure on the converted region, the resulting region would be the
- same as the bitmap. This procedure may be useful if you want to test the mouse
- for hits against the black pixels in a bitmap, or drag the outline of a bitmap
- using DragGrayRegion.
- _______________________________________________________________________________
-
- æKY Checking…that…QuickDraw…is…Done
- æC »Checking that QuickDraw is Done Color QuickDraw
- _______________________________________________________________________________
-
- A new function, QDDone, checks to see whether QuickDraw drawing operations have
- completed in a grafport. This is useful if you are executing in an environment
- with a graphics accelerator, where drawing operations may proceed
- asynchronously.
-
- _______________________________________________________________________________
-
- æKY New…Color…Quickdraw…Routines
- æC »NEW COLOR QUICKDRAW ROUTINES Color QuickDraw
- _______________________________________________________________________________
-
- Since using direct color only requires internal Color QuickDraw changes to
- recognize direct pixel values, no new routines are defined for direct color.
- _______________________________________________________________________________
-
- æKY New…QuickDraw…Result…Codes
- æC »New QuickDraw Result Codes Color QuickDraw
- _______________________________________________________________________________
-
- QuickDraw uses stack space for work buffers. For complex operations such as
- depth conversion, dithering, or image resizing, stack space may not be
- sufficient. Color QuickDraw now attempts to get temporary memory from
- MultiFinder. If that is still not enough, or if MultiFinder is not present,
- Color QuickDraw returns
-
- QDErr -149 Insufficient stack
-
- One recourse for the application is to divide the operation—for example divide
- the image into left and right halves—and try again. An alternative is to make
- the stack larger.
-
- While recording drawing operations into an open region the resulting region
- description might overflow the 64 KB limit. Should this happen Color QuickDraw
- will return -147 in QDErr:
-
- QDErr -147 Region too big
-
- Since the resulting region is potentially corrupt, closeRgn returns an empty
- region if it detects QDErr has been set to -147.
-
- _______________________________________________________________________________
-
- æKY Creating…an…Extended…PICT2…Picture
- æC »Creating an Extended PICT2 Picture Color QuickDraw
- _______________________________________________________________________________
-
- FUNCTION OpenCPicture (newHeader: PICT2Header) : PicHandle;
-
- OpenCPicture performs the same functions as OpenPicture, except that it creates
- an extended PICT2 format file, with pixel resolution and the best imaging
- rectangle stored in the header.
-
- You pass a PICT2Header record describing the rectangle that encloses the drawing
- information you supply for the picture, and you pass horizontal and vertical
- resolutions describing the best resolution for displaying the picture in the
- rectangle. The structure of a PICT2Header record is
-
- PICT2Header =
- RECORD
- SrcRect: Rect {source rectangle for best display}
- {at HRes, VRes resolution}
- hRes: Fixed; {best horizontal resolution}
- vRes: Fixed; {best vertical resolution}
- version: word; {set to -2}
- reserved: word; {reserved for future use}
- END;
-
- Note that the order the information is recorded in the PICT2 header differs from
- the order in this record. See the sample PICT2 file in “The Extended PICT2
- Format.”
-
- As with OpenPicture, you close the picture using ClosePicture, and draw it using
- DrawPicture.
-
- _______________________________________________________________________________
-
- æKY From…Bitmap…to…Region
- æC »From Bitmap to Region Color QuickDraw
- _______________________________________________________________________________
-
- FUNCTION BitMapToRegion (region:RGNHandle; bMap:BitMap) : OSErr;
-
- The region parameter must be a valid region handle created with a NewRgn
- function. The old region contents are lost.
-
- The bMap parameter may either be a BitMap or PixMap record. If a PixMap record
- is passed, its pixel size (bits per pixel) must be 1.
-
- Result codes
- rgnTooBigErr -500 BitMap would convert into a region greater
- than 32 KB
- pixmapTooDeepErr -148 PixMap record is deeper than 1 bit per pixel
- _______________________________________________________________________________
-
- æKY Drawing…Completion
- æC »Drawing Completion Color QuickDraw
- _______________________________________________________________________________
-
- FUNCTION QDDone (port:GrafPtr) : Boolean;
-
- The QDDone function returns true if drawing operations have completed in the
- designated port, false if any remain to be executed. This call may be useful if
- a graphics accelerator is present and operating asynchronously. You can ensure
- that all drawing has been done and avoid the possibility that new drawing
- operations might be overlaid by previously issued but unexecuted operations.
-
- _______________________________________________________________________________
-
- æKY Reporting…Data…Structure…Changes
- æC »Reporting Data Structure Changes Color QuickDraw
- _______________________________________________________________________________
-
- The following routines can be used to mitigate possible side effects of directly
- changing a CLUT, PixPat, GrafPort, or GDevice data structure.
-
- PROCEDURE CTabChanged (ctab: CTabHandle);
-
- Call CTabChanged after modifying the content of a color table. CTabChanged calls
- GetCTSeed to get a new seed for the color table and notifies QuickDraw of the
- change.
-
- PROCEDURE PixPatChanged (ppat: PixPatHandle);
-
- Call PixPatChanged after modifying a PixPat data structure or any of its
- substructures (patMap or patData records). PixPatChanged sets the patXValid flag
- to -1 and notifies QuickDraw of the change.
-
- If your application changes the pmTable field of the pixel pattern’s patMap, it
- should call PixPatChanged. However, if your application changes the content of
- the CLUT referenced by pmTable, it should call CTabChanged as well.
-
- PROCEDURE PortChanged (port: GrafPtr);
-
- Call PortChanged after modifying the content of a port or any of its
- substructures. PortChanged notifies QuickDraw of the change.
-
- None of the PixPat records pointed to by a CGrafPort record should be changed
- directly. Use PenPixPat and BackPixPat instead. However, if your application
- changes the content of one of the PixPat records, it should call PixPatChanged.
-
- If your application changes the pmTable field of the port’s PixMap, it should
- call PortChanged. However, if your application changes the content of the color
- table referenced by pmTable, it should call CTabChanged as well.
-
- PROCEDURE GDeviceChanged (gdh: GDHandle);
-
- Call GDeviceChanged after modifying a gDevice graphics device record or any of
- its substructures. GDeviceChanged notifies QuickDraw of the change.
-
- If your application changes the pmTable field of the graphics device record’s
- PixMap, it should call GDeviceChanged. However, if your application changes the
- content of the color table referenced by gdPMap, it should call CTabChanged as
- well.
-
- _______________________________________________________________________________
-
- æKY The…Extended…PICT2…Format
- æC »THE EXTENDED PICT2 FORMAT Color QuickDraw
- _______________________________________________________________________________
-
- The PICT2 format presented in the Color QuickDraw chapter of Volume V has been
- extended to allow storing direct PixMaps and for maintaining resolution and
- imaging rectangle information.
-
-
- The major differences between version 1 and version 2 pictures are that three
- opcodes previously listed as reserved have been defined, and one defined opcode
- has been redefined:
-
- Opcode 2C signals font name information.
-
- Opcodes 9A and 9B now define direct-pixel pictures, with PixMaps containing
- three components, directly specifying RGB values.
-
- Opcode 0C00 still signifies a header record, and it is still 24 bytes, but the
- contents have changed.
-
- This section presents a sample PICT file and the extended PICT2 opcodes.
-
- _______________________________________________________________________________
-
- æKY Sample…Extended…PICT2…File
- æC »Sample Extended PICT2 File Color QuickDraw
- _______________________________________________________________________________
-
- An example of an extended PICT2 data file that can display a single direct-pixel
- image is shown in Table 1.
-
- Table 1. PICT file example
- ________________________________________________________________________
- Size Name Description
- (in bytes)
- 2 picSize low word of picture size
- 8 picFrame rectangular bounding box of picture, at
- 72 dpi
-
- Picture Definition Data:
-
- 2 version op version opcode = $0011
- 2 version version number = $02FF
- 2 Header op header opcode = $0C00
- 2 version set to -2 for extended PICT2
- 2 reserved reserved for future Apple use
- 4 HRes native horizontal resolution
- 4 VRes native vertical resolution
- 8 SrcRect native source rectangle
- 4 reserved reserved for future Apple use
- 2 opbitsRect bitMap opcode = $009A for direct
- 4 baseAddr for direct must be $000000FF. See Table 4
- 2 rowBytes integer, must have high bit set to signal pixMap
- 8 bounds rectangle, bounding rectangle at source resolution
- 2 pmVersion integer, pixMap version number = 0
- 2 packType integer, defines packing format
- 4 packSize LongInt, length of pixel data = 0
- 4 hRes fixed, horizontal resolution (dpi) of source data,
- normally $00480000 (72 dpi)
- 4 vRes fixed, vertical resolution (dpi) of source data,
- normally $00480000 (72 dpi)
- 2 pixelType integer, defines pixel type; 16 for direct
- 2 pixelSize integer, number of bits in pixel; 16 or 32 for direct
- 2 cmpCount integer, number of components in pixel; 3 for direct
- 2 cmpSize integer, number of bits per component; 5 or 8 for direct
- 4 planeBytes LongInt, offset to next plane = 0
- pmTable color table = 0
- pmReserved reserved = 0
- 4 ctSeed LongInt, color table seed
- 2 ctFlags integer, flags for color table
- 2 ctSize integer, number of entries in ctTable –1
- (ctSize+1) * 8 ctTable color lookup table data
- 8 srcRect rectangle, source rectangle at source resolution
- 8 dstRect rectangle, destination rectangle at 72 dpi resolution
- 2 mode integer, transfer mode see Table 5
- pixData pixel data
- 2 endPICT op end-of-picture opcode = $00FF
-
- _______________________________________________________________________________
-
- æKY PICT2…Opcode…Types
- æC »PICT2 Opcode Types Color QuickDraw
- _______________________________________________________________________________
-
- The following description shows the new PICT2 format, with changes from the
- description in Volume V indicated by an asterisk.
-
-
- The opcode information in Table 3x is provided for the purpose of debugging
- application-generated PICT files. Your application should generate and read PICT
- files only by using standard QuickDraw or Color QuickDraw routines (OpenPicture,
- OpenCPicture, ClosePicture). The data types listed in Table 2x are used in the
- Table 3x opcode definitions.
-
- Table 2. Data types
- ________________________________________________________________________
- Type Size
- v1 opcode 1 byte
- v2 opcode 2 bytes
- integer 2 bytes
- long integer 4 bytes
- mode 2 bytes
- point 4 bytes
- 0..255 1 byte
- –128..127 1 byte (signed)
- rect 8 bytes (top, left, bottom, right: integer)
- poly 10+ bytes
- region 10+ bytes
- fixed-point number 4 bytes
- pattern 8 bytes
- rowbytes 2 bytes (always an even quantity)
- ________________________________________________________________________
-
- _______________________________________________________________________________
-
- æKY Extended…PICT2…Opcodes
- æC »Extended PICT2 Opcodes Color QuickDraw
- _______________________________________________________________________________
-
- Valid picture opcodes are listed in Table 3. New opcodes or those altered to
- extend the PICT2 format are indicated by a leading asterisk (*). The unused
- opcodes found throughout the table are reserved for Apple use. The length of the
- data that follows these opcodes is pre-defined, so if they are encountered in
- pictures, they can simply be skipped. By default, QuickDraw reads and then
- ignores these opcodes.
-
-
-
- Table 3. PICT opcodes
- ________________________________________________________________________
- Opcode Name Description Data Size
- (in bytes)
- $0000 NOP nop 0
- $0001 Clip clip region size + data
- $0002 BkPat background pattern 8
- $0003 TxFont text font (word) 2
- $0004 TxFace text face (byte) 1
- $0005 TxMode text mode (word) 2
- $0006 SpExtra space extra (fixed point) 4
- $0007 PnSize pen size (point) 4
- $0008 PnMode pen mode (word) 2
- $0009 PnPat pen pattern 8
- $000A FillPat fill pattern 8
- $000B OvSize oval size (point) 4
- $000C Origin dh, dv (word) 4
- $000D TxSize text size (word) 2
- $000E FgColor foreground color (long) 4
- $000F BkColor background color (long) 4
- $0010 TxRatio numer (point), denom (point) 8
- $0011 Version version (byte) 1
- $0012 BkPixPat color background pattern variable:
- see Table 4
- $0013 PnPixPat color pen pattern variable:
- see Table 4
- $0014 FillPixPat color fill pattern variable:
- see Table 4
- $0015 PnLocHFrac fractional pen position 2
- $0016 ChExtra extra for each character 2
- $0017 reserved opcode 0
- $0018 reserved opcode 0
- $0019 reserved opcode 0
- $001A RGBFgCol RGB foreColor variable:
- see Table 4
- $001B RGBBkCol RGB backColor variable:
- see Table 4
- $001C HiliteMode hilite mode flag 0
- $001D HiliteColor RGB hilite color variable:
- see Table 4
- $001E DefHilite Use default hilite color 0
- $001F OpColor RGB OpColor for variable:
- arithmetic modes see Table 4
- $0020 Line pnLoc (point), newPt (point) 8
- $0021 LineFrom newPt (point) 4
- $0022 ShortLine pnLoc (point, dh, dv 6
- (-128..127)
- $0023 ShortLineFrom dh, dv (-128..127) 2
- $0024 reserved opcode + 2 bytes data 2+ data
- length + data length
- $0025 reserved opcode + 2 bytes data 2+ data
- length + data length
- $0026 reserved opcode + 2 bytes data 2+ data
- length + data length
- $0027 reserved opcode + 2 bytes data 2+ data
- length + data length
- $0028 LongText txLoc (point), count 5 + text
- (0..255), text
- $0029 DHText dh (0..255), count 2 + text
- (0..255), text
- $002A DVText dv (0..255), count 2 + text
- (0..255), text
- $002B DHDVText dh, dv (0..255), count 3 + text
- (0..255), text
- $002C *fontName data length (word), old font 5+ name
- ID (word), name length (byte), length
- font name
- $002D reserved opcode + 2 bytes data 2+ data
- length + data length
- $002E reserved opcode + 2 bytes data 2+ data
- length + data length
- $002F reserved opcode + 2 bytes data 2+ data
- length + datalength
- $0030 frameRect rect 8
- $0031 paintRect rect 8
- $0032 eraseRect rect 8
- $0033 invertRect rect 8
- $0034 fillRect rect 8
- $0035 reserved opcode + 8 bytes data 8
- $0036 reserved opcode + 8 bytes data 8
- $0037 reserved opcode + 8 bytes data 8
- $0038 frameSameRect rect 0
- $0039 paintSameRect rect 0
- $003A eraseSameRect rect 0
- $003B invertSameRect rect 0
- $003C fillSameRect rectangle 0
- $003D reserved opcode 0
- $003E reserved opcode 0
- $003F reserved opcode 0
- $0040 frameRRect rect (see Note # 5 ) 8
- $0041 paintRRect rect (see Note # 5 ) 8
- $0042 eraseRRect rect (see Note # 5 ) 8
- $0043 invertRRec rect (see Note # 5 ) 8
- $0044 fillRRect rect (see Note # 5 ) 8
- $0045 reserved opcode + 8 bytes data 8
- $0046 reserved opcode + 8 bytes data 8
- $0047 reserved opcode + 8 bytes data 8
- $0048 frameSameRRect rect 0
- $0049 paintSameRRect rect 0
- $004A eraseSameRRect rect 0
- $004B invertSameRRect rect 0
- $004C fillSameRRect rect 0
- $004D reserved opcode 0
- $004E reserved opcode 0
- $004F reserved opcode 0
- $0050 frameOval rect 8
- $0051 paintOval rect 8
- $0052 eraseOval rect 8
- $0053 invertOval rect 8
- $0054 fillOval rect 8
- $0055 reserved opcode + 8 bytes data 8
- $0056 reserved opcode + 8 bytes data 8
- $0057 reserved opcode + 8 bytes data 8
- $0058 frameSameOval rect 0
- $0059 paintSameOval rect 0
- $005A eraseSameOval rect 0
- $005B invertSameOval rect 0
- $005C fillSameOval rect 0
- $005D reserved opcode 0
- $005E reserved opcode 0
- $005F reserved opcode 0
- $0060 frameArc rect, startAngle, arcAngle 12
- $0061 paintArc rect, startAngle, arcAngle 12
- $0062 eraseArc rect, startAngle, arcAngle 12
- $0063 invertArc rect, startAngle, arcAngle 12
- $0064 fillArc rect, startAngle, arcAngle 12
- $0065 reserved opcode + 12 bytes 12
- $0066 reserved opcode + 12 bytes 12
- $0067 reserved opcode + 12 bytes 12
- $0068 frameSameArc rect 4
- $0069 paintSameArc rect 4
- $006A eraseSameArc rect 4
- $006B invertSameAr rect 4
- $006C fillSameArc rect 4
- $006D reserved opcode + 4 bytes 4
- $006E reserved opcode + 4 bytes 4
- $006F reserved opcode + 4 bytes 4
- $0070 framePoly poly polygon size
- $0071 paintPoly poly polygon size
- $0072 erasePoly poly polygon size
- $0073 invertPoly poly polygon size
- $0074 fillPoly poly polygon size
- $0075 reserved opcode + poly
- $0076 reserved opcode + poly
- $0077 reserved opcode word + poly
- $0078 frameSamePoly (not yet implemented: 0
- same as 70, etc)
- $0079 paintSamePoly (not yet implemented) 0
- $007A eraseSamePoly (not yet implemented) 0
- $007B invertSamePoly (not yet implemented) 0
- $007C fillSamePoly (not yet implemented) 0
- $007D reserved opcode 0
- $007E reserved opcode 0
- $007F reserved opcode 0
- $0080 frameRgn rgn region size
- $0081 paintRgn rgn region size
- $0082 eraseRgn rgn region size
- $0083 invertRgn rgn region size
- $0084 fillRgn rgn region size
- $0085 reserved opcode + rgn region size
- $0086 reserved opcode + rgn region size
- $0087 reserved opcode + rgn region size
- $0088 frameSameRgn (not yet implemented- 0 same as 80, etc.)
- $0089 paintSameRgn (not yet implemented) 0
- $008A eraseSameRgn (not yet implemented) 0
- $008B invertSameRgn (not yet implemented) 0
- $008C fillSameRgn (not yet implemented) 0
- $008D reserved opcode 0
- $008E reserved opcode 0
- $008F reserved opcode 0
- $0090 BitsRect copybits, rect clipped variable:
- see Table 4
- $0091 BitsRgn copybits, rgn clipped variable:
- see Table 4
- $0092 reserved opcode + 2 bytes data 2+ data
- length + data length
- $0093 reserved opcode + 2 bytes data 2+ data
- length + data length
- $0094 reserved opcode + 2 bytes data 2+ data
- length + data length
- $0095 reserved opcode + 2 bytes data 2+ data
- length + data length
- $0096 reserved opcode + 2 bytes data 2+ data
- length + data length
- $0097 reserved opcode + 2 bytes data 2+ data
- length + data length
- $0098 PackBitsRect packed copybits, rect variable:
- clipped see Table 4
- $0099 PackBitsRgn packed copybits, rect variable:
- clipped see Table 4
- $009A *DirectBitsRect PixMap, srcRect, dstRect, mode variable
- (Word), PixData see Table 4
- $009B *DirectBitsRgn PixMap, srcRect, dstRect, mode variable
- (Word), maskRgn, PixData see Table 4
- $009C reserved opcode + 2 bytes data 2+ data
- length + data length
- $009D reserved opcode + 2 bytes data 2+ data
- length + data length
- $009E reserved opcode + 2 bytes data 2+ data
- length + data length
- $009F reserved opcode + 2 bytes data 2+ data
- length + data length
- $00A0 ShortComment kind (word) 2
- $00A1 LongComment kind (word), size 4+data
- (word), data
- $00A2 reserved opcode + 2 bytes data 2+ data
- length + data length
- : : :
- : : :
- $00AF reserved opcode + 2 bytes data 2+ data
- length + data length
- $00B0 reserved opcode 0
- : : :
- : : :
- $00CF reserved opcode 0
- $00D0 reserved opcode + 4 bytes data 4+ data
- length + data length
- : : :
-
- : : :
-
- $00FE reserved opcode + 4 bytes data 4+ data
- length + data length
- $00FF opEndPic end of picture 2
- $0100 reserved opcode + 2 bytes data 2
- : : :
- : : :
-
- $01FF reserved opcode + 2 bytes data 2
- $0200 reserved opcode + 4 bytes data 4
- : : :
-
- $0BFF reserved opcode + 4 bytes data 22
- $0C00 *HeaderOp Version (word), reserved 24
- (word), Hres, VRes (Fixed),
- SrcRect (Rect), reserved (Long)
- $0C01 reserved opcode + 4 bytes data 24
- : : :
-
- $7F00 reserved opcode + 254 bytes data 254
- : : :
-
- $7FFF reserved opcode + 254 bytes data 254
- $8000 reserved opcode 0
- : : :
-
- $80FF reserved opcode 0
- $8100 reserved opcode + 4 bytes data 4+ data
- length + data length
- : : :
-
- $FFFF reserved opcode + 4 bytes data 4+ data
- length + data length
- ________________________________________________________________________
-
- Notes to Table 3
-
- 1. Remember, opcode size is 1 byte for PICT, 2 bytes for PICT2.
-
- 2. Because opcodes must be word aligned in version 2 pictures, a byte of 0
- (zero) data is added after odd-size data.
-
- 3. The size of reserved opcodes has been defined. They can occur only in version
- 2 pictures.
-
- 4. All unused opcodes are reserved for future Apple use and should not be used.
-
- 5. For opcodes $0040–$0044: rounded-corner rectangles use the setting of the
- ovSize point (refer to opcode $000B)
- 6. For opcodes $0090 and $0091: data is unpacked. These opcodes can only be used
- for rowbytes less than 8.
-
- 7. For opcodes $0100–$7FFF: the amount of data for opcode $nnXX = 2 * nn bytes.
-
-
-
- The New Opcodes: Expanded Format
-
- The expanded format of the version 2 PICT opcodes is shown in Table 4 below.
-
- Table 4. Data Format of Version 2 PICT Opcodes
- ________________________________________________________________________
- Opcode Name Description Reference
- to Notes
-
- $002C fontName ID and name of font See Note 1
- $009A DirectBitsRect PixMap, src and dst See Note 2
- rects, mode, and PixData
- $009B DirectBitsRgn PixMap, src and dst See Note 2
- rects, mode, maskRgn,
- PixData
- $0C00 HeaderOp Version (Word), reserved Word, See Note 3
- Hres, VRes (Fixed), SrcRect
- (Rect), reserved (Word)
-
- ________________________________________________________________________
-
- Notes to Table 4
-
- 1. The fontName information begins with a word containing the field’s data
- length, followed by a word containing the old font ID, a byte containing the
- length of the font name, and the font name itself.
-
-
- 2. Unlike previous Bits opcodes, the DirectBits opcodes store the baseAddr field
- of the pixMap structure in a PICT2. For compatibility with existing systems the
- baseAddr field is set to $000000FF. On systems without direct pixel support,
- opcodes $009A and $009B read a word from the picture and then skip that much
- data. The next opcode fetched from the picture is $00FF, which terminates
- picture playback.
-
-
- The DirectBitsRect opcode will be followed by this structure:
-
-
- pixMap: { described below }
- srcRect: Rect; { source rectangle }
- dstRect: Rect; { destination rectangle }
- mode: word; { transfer mode }
- pixData: { described below }
-
- The DirectBitsRgn opcode will be followed by this structure:
-
-
- pixMap: { described below }
- srcRect: Rect; { source rectangle }
- dstRect: Rect; { destination rectangle }
- mode: word; { transfer mode }
- maskRgn: Region; { region for masking }
- pixData: { described below }
-
- The following pseudocode describes the pixData data type.
-
-
- pixData:
-
- If packType = 1 (unpacked) or rowbytes < 8 then data is unpacked, and
- data size = rowBytes * (bounds.bottom-bounds.top);
-
- If packType = 2 (drop pad byte) then the high-order pad byte of a
- 32-bit direct pixel is dropped, and
- data size = (3/4) * rowBytes * (bounds.bottom-bounds.top);
-
- If packType > 2 (packed) then
- Image contains (bounds.bottom-bounds.top) packed scanlines
- Each scanline consists of [byteCount] [data].
- If rowBytes > 250 then byteCount is a word, else it is a byte.
-
- In a picture, the packType field of a pixMap specifies the manner in which the
- pixData was compressed. To facilitate banding of images when memory is short,
- all data compression is done on a scanline basis. The currently defined packing
- schemes are:
-
- 1 = no packing
-
- 2 = remove pad byte—supported only for 32-bit pixels (24-bit data)
-
- 3 = run length encoding by pixelSize chunks, one scanline at a time—supported
- only for 16-bit pixels
-
- 4 = run length encoding all of one component at a time, one scanline at a time,
- red component first—supported only for 32-bit pixels (24-bit data)
-
- For future compatibility, other packType values skip scanline data and draw
- nothing. Since pixMap data in memory is assumed to be unpacked regardless of the
- packType field value, packType can be used to tell the picture-recording
- mechanism what packing technique to use on that data. A packType value of zero
- in memory indicates that the default packing scheme should be used. As a general
- rule, using the default packing scheme is recommended. Currently, the default
- packType for pixelSize=16 is scheme 3, for pixelSize=32 it is scheme 4.
- Regardless of the setting of packType at the time of picture recording, the
- packType actually used to save the image will be recorded in the picture.
-
- Since each scanline of packed data is preceded by a byte count, packSize is not
- used and must be zero for future compatibility.
-
- When the pixel type is direct chunky, cmpCount * cmpSize ≤ pixelSize. For
- storing 24 bit data in a 32 bit pixel, cmpSize would be eight and cmpCount would
- be three. If you set cmpCount = 4 then the high byte will be compressed by
- packing scheme 4 and stored in the picture.
-
- 3. The headerOp information is passed to the OpenCPicture routine as a
- PictureHeader record, which has the structure:
-
- TYPE
- PictureHeader = Record
- version: word;
- reserved: word;
- HRes: Fixed;
- VRes: Fixed;
- SrcRect: Rect
- END;
-
-
- _______________________________________________________________________________
-
- æKY Summary…of…Color…Quickdraw…Changes
- æC »SUMMARY OF COLOR QUICKDRAW CHANGES Color QuickDraw
- _______________________________________________________________________________
-
- The following cards summarize the constants, data types, and routines for Color
- Quickdraw.
- _______________________________________________________________________________
-
- æKY Color…Quickdraw…Constants
- æC »Constants Color QuickDraw
- _______________________________________________________________________________
-
- CONST
-
- {New Constants for Color QuickDraw}
-
- ditherCopy = 64; {Dither mode for Copybits}
- RGBDirect = 16; {16 & 32 bits/pixel pixelType value}
- _______________________________________________________________________________
-
- æKY Color…Quickdraw…Data…Types
- æC »Data Types Color QuickDraw
- _______________________________________________________________________________
-
- PICT2Header =
- RECORD
- version: word; {set to -2}
- reserved: word; {reserved for future use}
- hRes: Fixed; {best horizontal resolution}
- vRes: Fixed; {best vertical resolution}
- SrcRect: Rect {source rectangle for best display}
- {at hRes, vRes resolution}
- END;
- _______________________________________________________________________________
-
- æKY Color…Quickdraw…Routines
- æC »Routines Color QuickDraw
- _______________________________________________________________________________
-
- FUNCTION OpenCPicture (newHeader: PICT2Header) : PicHandle;
- FUNCTION GetCTable (ctID: Integer) : CTabHandle;
- FUNCTION BitMapToRegion (region:RGNHandle; bMap:BitMap) : OSErr;
- PROCEDURE CTabChanged (ctab: CTabHandle);
- PROCEDURE PixPatChanged (ppat: PixPatHandle);
- PROCEDURE GDeviceChanged (gdh: GDHandle);
- FUNCTION QDDone (port:GrafPtr) : Boolean;
- _______________________________________________________________________________
-
- æKY Color…Quickdraw…Result…Codes
- æC »Result Codes Color QuickDraw
- _______________________________________________________________________________
-
- QDErr -147 Region too big
- pixmapTooDeepErr -148 PixMap record is deeper than 1 bit per pixel
- QDErr -149 Insufficient stack
- rgnTooBigErr -500 BitMap would convert into a region greater than 32 KB
- _______________________________________________________________________________
-
-
- æKY CompatibilityGuidelines
- æC
- _______________________________________________________________________________
-
- COMPATIBILITY GUIDELINES
- _______________________________________________________________________________
-
- About…the…Compatibility…Guidelines…Chapter
- About…Compatibility
- Using…Memory…Wisely
- Using…Assembly…Language
- Accessing…Hardware
- Using…Low-Memory…Global…Variables
- Determining…Whether…a…Trap…Is…Available
- Running…in…System…Software…Version…7.0
- Allowing…Multiple…Applications
- Supporting…Standard…AppleEvents
- Selecting…AppleEvents…to…Support
- Isolating…User…Interface…Code
- Modifying…the…Event…Loop
- Indicating…an…Application…Is…AppleEvent-Aware
- Removing…Font…Size…Restrictions
- Operating…With…Virtual…Memory
- Localizing…Macintosh…Programs
- General…Guidelines…for…Compatibility
- Other…Localization…Tools
- Running…Macintosh…Programs…Under…A/UX
- How…the…A/UX…Toolbox…Works
- Using…the…A/UX…Toolbox
- A/UX…Compatibility…Guidelines
- About…the…Gestalt…Manager
- Using…the…Gestalt…Manager
- Determining…Features…of…the…Operating…Environment
- Determining…Whether…Gestalt…Is…Available
- Interpreting…Gestalt…Responses
- Interpreting…Responses…to…Environmental…Selectors
- Interpreting…Responses…to…Informational…Selectors
- Adding…Gestalt…Selectors
- Modifying…Gestalt…Selectors
- Specifying…Gestalt…Selector…Functions
- Gestalt…Manager…Routines
- Getting…Information…About…the…Operating…Environment
- Adding…Selector…Codes
- Modifying…Selector…Codes
- Summary…of…the…Gestalt…Manager
- Gestalt…Manager…Constants
- Gestalt…Manager…Routines…Summary
- Gestalt…Manager…Result…Codes
- _______________________________________________________________________________
-
-
-
- æKY About…the…Compatibility…Guidelines…Chapter
- æC »ABOUT THIS CHAPTER Compatibility Guidelines
- _______________________________________________________________________________
-
- This chapter describes how you can write applications that have the greatest
- chance of operating on all models of the Macintosh® computer, regardless of the
- hardware components found on any particular machine and of the available system
- software, managers, and device drivers. It addresses how you can take advantage
- of features that are new to system software version 7.0 in ways that are least
- likely to cause problems for users who are not running version 7.0. In a word,
- this chapter provides as much advice as possible to help you achieve maximum
- compatibility for your applications on all Macintosh computers, including those
- running version 7.0.
-
- System software version 7.0 provides the most important test of software
- compatibility since the introduction of the Macintosh II, and you must
- understand how you may need to revise your current applications so that they
- operate correctly with this new system software. Fortunately, if you have
- followed the guidelines given in previous volumes of Inside Macintosh, your
- applications stand a very good chance of working correctly in version 7.0
- without any modification whatsoever. However, version 7.0 introduces many new
- features and capabilities that you may wish to use in your applications, without
- sacrificing compatibility with earlier versions of system software. This chapter
- provides a number of additional guidelines to help you revise existing
- applications to take advantage of version 7.0 features while retaining
- compatibility with previous system software.
-
- System software version 7.0, with its multitasking environment and its new
- emphasis on communication and cooperation among applications, places certain
- responsibilities on applications. As a result, you must be more aware than ever
- of the programming shortcuts that can result in incompatibility.
-
- This chapter focuses on several aspects of writing software that is compatible
- with all Macintosh computers:
-
- • what can cause compatibility problems and how in general to avoid those
- problems
-
- • how to write applications that execute in both version 6.0 and version
- 7.0 system software
-
- • how to determine what software and hardware features are available on a
- particular machine
-
- • how to write applications that execute under A/UX®, Apple’s version of
- the UNIX® operating system
-
- • how to write software that can be easily modified for use in other
- countries
-
- This chapter also describes the Gestalt Manager, a set of three new Operating
- System functions that provide applications with a simple and efficient method
- for determining what software and hardware features are available on a given
- machine. You need to use the Gestalt Manager if your application takes advantage
- of particular hardware components (such as a floating-point unit) or software
- modules (such as Color QuickDraw™) that are not available on all Macintosh
- computers. Your application can also use the Gestalt Manager to inform the
- Operating System (and hence other applications) that it is present in the
- current environment.
-
- The Gestalt Manager is available in system software version 7.0. It is also
- included in system software versions 6.0.4 and 6.0.5, and in ROM on two
- machines, the Macintosh IIci and the Macintosh Portable. Your development system
- may supply code that allows you to call Gestalt on earlier system software
- versions; check the documentation provided with your development system to see
- if this is possible. Of course, since you cannot use Gestalt to determine if it
- is present, you must do that in some other way; one such method is illustrated
- in
- “Determining Whether Gestalt Is Available” later in this chapter.
-
- You need to read this chapter if you are interested in writing applications that
- execute on as many Macintosh computers as possible or under alternate operating
- systems such as A/UX. In particular, if you wish to enhance an existing product
- so that it supports new features of system software version 7.0 but also
- executes correctly in earlier versions of system software, or if you wish to
- write a new product that executes only in version 7.0, you should look at
- “Running In System Software Version 7.0.” You should read the sections on the
- Gestalt Manager later in this chapter if you need to take advantage of specific
- software or hardware features that may not be present on all versions of the
- Macintosh, or if you wish to inform other applications of the presence of your
- application in the operating environment.
-
- If you want your applications to run in system software versions earlier than
- 6.0.4 (where the Gestalt function is not available), you should be familiar with
- the Environs procedure, discussed in the Operating System Utilities chapter of
- Volumes II and IV, and the SysEnvirons function, discussed in the Compatibility
- Guidelines chapter of Volume V. Both Environs and SysEnvirons perform the kind
- of function that Gestalt performs—they allow you to determine what features are
- available on a specific machine. For reasons outlined later, however, you should
- not use either of these routines if the Gestalt function is available.
-
- Unfortunately, no single chapter can provide all the information you need to
- achieve the greatest possible compatibility for your applications. Most of the
- subsequent chapters in this volume (and indeed all previous volumes of Inside
- Macintosh) contain numerous warnings and guidelines that you should heed if you
- wish to increase the likelihood that your applications will execute correctly on
- all members of the Macintosh family and under alternate operating systems such
- as A/UX. The Memory Management chapter in this volume, for example, contains a
- fuller account of 32-bit clean programming than is given here and is essential
- reading for all developers. (An application is 32-bit clean if it can use all 32
- bits of a handle or pointer for memory addressing.) Similarly, the guidelines
- given in this chapter on writing A/UX-compatible Macintosh programs summarize
- and complement, but do not replace, the discussion in the separate publication
- A/UX Toolbox: Macintosh ROM Interface. So the complete story on Macintosh
- software compatibility does not end with this chapter, but it does begin here.
-
- _______________________________________________________________________________
-
- æKY About…Compatibility
- æC »ABOUT COMPATIBILITY Compatibility Guidelines
- _______________________________________________________________________________
-
- Compatibility is the ability of a program to execute properly in different
- operating environments. Compatibility is important if you want to write software
- that runs, with little or no modification, on all members of the Macintosh
- family and in all system software versions. If you want to take advantage of
- particular software or hardware features that may not be present on all
- Macintosh computers, you need to know how to determine when those features are
- available.
-
- To appreciate why compatibility is a real and sometimes vexing concern, imagine
- that from all the Macintosh computers currently in operation in the world, you
- were to choose two at random. You would quite likely find a great number of
- differences in the hardware and software configurations on those two machines.
- You might find different CPUs, different memory management units (MMUs),
- different amounts of RAM, different shapes and sizes of monitors, and so forth.
- You are also likely to find different versions of system software, different ROM
- versions, different AppleTalk® drivers, different versions of managers,
- different printer interfaces, and so forth. Ideally, you want your product to
- run on both of those machines, regardless of the many significant differences
- between them. If you succeed in writing your application so that it does operate
- on both of those machines, you have succeeded in writing compatible software.
-
- This section provides a number of guidelines that you should follow if you want
- your applications to run on the greatest number of Macintosh computers. Some of
- these guidelines are quite general and apply to all programs; some apply only if
- you are programming in assembly language.
-
- One key to achieving compatibility is not to depend on things that may change.
- Inside Macintosh contains numerous warnings about which information is likely to
- change. As the Operating System and User Interface Toolbox evolve to accommodate
- the needs of developers and users, many of the elements will vary. Whenever
- possible, Apple strives to add features without altering existing interfaces. In
- general, you can assume that Operating System and Toolbox routines are less
- likely to change than data structures. Therefore, you should never manipulate
- data structures directly, even if their structure is documented. Instead, you
- should manipulate those structures only indirectly, by calling Operating System
- and Toolbox routines that achieve the desired effect. In particular, you should
- never alter any portion of a data structure marked as unused or reserved.
-
- Another key to writing compatible code is to code defensively. Do not assume
- that users perform actions in a particular order, and do not assume that
- function and procedure calls always succeed. You should always test the return
- values of routines for errors, as illustrated in most of the code samples
- presented in this volume.
-
- _______________________________________________________________________________
-
- æKY Using…Memory…Wisely
- æC »Using Memory Wisely Compatibility Guidelines
- _______________________________________________________________________________
-
- A major cause of compatibility problems, especially in connection with
- applications running in the A/UX operating system, is misuse of the Memory
- Manager . Here are some important points to keep in mind:
-
- • Do not set bits in master pointers directly. Use Memory Manager traps (for
- example, HLock) instead.
-
- • Always check the handle or pointer returned by a routine to make certain
- that it is not NIL. A NIL handle may indicate that a memory allocation
- failed, or that a requested resource could not be found.
-
- • Always check that a handle marked as purgeable has not been purged before
- using that handle. For example:
-
- IF myHandle^ <> NIL THEN {handle not purged}
-
- • Do not create your own handles; instead, use the Memory Manager function
- NewHandle.
-
- • Never make assumptions about the contents of Memory Manager data structures.
-
- If you have followed all these guidelines, it is likely that your application is
- 32-bit clean, that is, that it operates correctly in an environment where all 32
- bits of handles and pointers are used to store memory addresses. In system
- software version 7.0 and A/UX, your applications must be 32-bit clean or they
- may not operate correctly. See the Memory Management chapter in this volume for
- more information about these points.
-
- _______________________________________________________________________________
-
- æKY Using…Assembly…Language
- æC »Using Assembly Language Compatibility Guidelines
- _______________________________________________________________________________
-
- In general, your software should not include 68000 instructions that require the
- processor to be in supervisor mode; these include instructions that modify the
- contents of the Status Register (SR). Programmers typically modify the SR only
- as a means of changing the Condition Code Register (CCR) half of the SR; in
- these cases, an instruction that addresses the CCR directly will work instead.
- Do not use the User Stack Pointer or turn interrupts on and off.
-
- If you wish to handle your own exceptions (thereby relying on the position of
- data in the exception’s local stack frame), be aware that exception stack frames
- vary within the 68000 family.
-
- In particular, don’t use the TRAP instruction. Also, the TAS instruction, which
- uses a special read-modify-write memory cycle, is not supported by the Macintosh
- SE and Macintosh II hardware.
-
- A memory management unit available in some Macintosh computers may prevent code
- from writing to addresses within code segments. Also, the 68020 and 68030 cache
- code as it is encountered. You should allocate data blocks on the stack or in
- heap blocks separate from the code, and your code should not modify itself.
-
- _______________________________________________________________________________
-
- æKY Accessing…Hardware
- æC »Accessing Hardware Compatibility Guidelines
- _______________________________________________________________________________
-
- You should never address hardware directly; whenever possible, use the routines
- provided by the various device drivers and managers to send data to the
- available hardware. The addresses of memory-mapped hardware (like the VIA1,
- VIA2, SCC, and so forth) are always subject to change, as is the hardware
- itself. More important, direct access to such hardware is not possible in every
- operating environment. In multiuser systems like A/UX, for instance, the
- operating system manipulates all hardware; applications simply cannot write
- directly to hardware addresses.
-
- You should also avoid writing directly to the screen. Use QuickDraw routines
- whenever possible to draw on the screen. If you absolutely must write directly
- to the screen, do not assume that the screen is a fixed size or that it is in a
- fixed location. The location, size, and bit depth of the screen differ in
- various machines. Instead, you should read the QuickDraw global variable
- screenBits.bounds to determine the size of the screen, screenBits.baseAddr to
- determine the start of the screen, and screenBits.rowBytes to determine the
- offset between rows. On machines with Color QuickDraw, the device list
- (described in the Graphics Devices chapter in this volume) tells the location,
- size, and bit depth of each screen, screenBits contains the location and size of
- the main device, and GrayRgn contains a region describing the shape and size of
- the desktop.
-
- _______________________________________________________________________________
-
- æKY Using…Low-Memory…Global…Variables
- æC »Using Low-Memory Global Variables Compatibility Guidelines
- _______________________________________________________________________________
-
- Don’t rely on low-memory global variables. Many of these variables have been
- previously documented in Inside Macintosh, but many have not. In particular, you
- must avoid undocumented low-memory global variables, because they are most
- likely to change. But you should even avoid well-known global variables, since
- they may not be available in all environments or in the future. In general, you
- can avoid using low-memory global variables by using available routines that
- return the same information. For example, the TickCount function returns the
- same value that is contained in the low-memory global variable Ticks. TickCount
- is available under A/UX, but Ticks is not. So you can increase the likelihood of
- compatibility with A/UX by using the routine and not the global variable.
-
- _______________________________________________________________________________
-
- æKY Determining…Whether…a…Trap…Is…Available
- æC »Determining Whether a Trap Is Available Compatibility Guidelines
- _______________________________________________________________________________
-
- One important way that the Operating System and Toolbox have changed through
- successive versions of the ROM and system software is by the addition of
- numerous new traps. For example, the Time Manager released with system software
- version 7.0 includes a new trap, InsXTime, that provides certain improvements
- over the existing trap, InsTime. By using InsXTime instead of InsTime, your
- application can ensure that the periodic actions it requests will execute at a
- fixed frequency that does not drift over time. Before using a trap that is not
- available on all machines, however, you need to determine whether it is
- available; if you call InsXTime on a machine that does not implement it, your
- program will crash.
-
- Your application can check the availability of a particular trap such as
- InsXTime in one of two ways. First, you can call the Gestalt function that is
- discussed later in this chapter to see if the appropriate version of the
- corresponding driver or manager is available. For example, the trap InsXTime is
- included in the extended Time Manager but not in earlier versions of the Time
- Manager. So you could use Gestalt to determine which version of the Time Manager
- is available in the current operating environment. If Gestalt reports that the
- extended Time Manager is present, you can safely call InsXTime to queue your
- request.
-
- There are several cases, however, in which you cannot use Gestalt to determine
- whether a specific trap is implemented. You cannot, for instance, use Gestalt to
- determine whether the Gestalt trap itself is available. In addition, the trap
- whose existence you wish to test might not be included in any manager or, if it
- is, there might not be a Gestalt selector code for that manager. The
- WaitNextEvent trap is a good example of this: there is no way, using Gestalt, to
- determine whether WaitNextEvent is available.
-
- The second way to determine the availability of a particular Operating System or
- Toolbox trap is by testing directly for the existence of the trap, using the
- technique illustrated in Listing 3-1. You should use this method to test whether
- Gestalt is available before calling Gestalt. You should also use it to test for
- the existence of traps not included in managers or drivers about which Gestalt
- can report. This listing illustrates how to test the availability of
- WaitNextEvent.
-
- Listing 3-1. Determining whether a trap is available
-
- USES
- Types, Traps, OSUtils;
-
- FUNCTION NumToolboxTraps: Integer;
- BEGIN
- IF NGetTrapAddress(_InitGraf,ToolTrap) =
- NGetTrapAddress($AA6E,ToolTrap) THEN
- NumToolboxTraps := $200
- ELSE
- NumToolboxTraps := $400;
- END;
-
- FUNCTION GetTrapType(theTrap: Integer): TrapType;
- CONST
- TrapMask = $0800;
- BEGIN
- IF BAND(theTrap,TrapMask) > 0 THEN
- GetTrapType := ToolTrap
- ELSE
- GetTrapType := OSTrap;
- END;
-
- FUNCTION TrapAvailable(theTrap: Integer): Boolean;
- VAR
- tType: TrapType;
- BEGIN
- tType := GetTrapType(theTrap);
- IF tType = ToolTrap THEN BEGIN
- theTrap := BAND(theTrap, $07FF);
- IF theTrap >= NumToolboxTraps THEN
- theTrap := _Unimplemented;
- END;
- TrapAvailable := NGetTrapAddress(theTrap, tType) <>
- NGetTrapAddress(_Unimplemented, ToolTrap);
- END;
-
- FUNCTION WNEAvailable: Boolean;
- CONST
- _WaitNextEvent = $A860; {trap number of WaitNextEvent}
- BEGIN
- WNEAvailable := TrapAvailable(_WaitNextEvent);
- END;
-
- The NumToolboxTraps function relies on the fact that the InitGraf trap (trap
- number $A86E) is always implemented. If the trap dispatch table is large enough
- (that is, has more than $200 entries), then $AA6E always points to either
- Unimplemented or something else, but never to InitGraf. As a result, you can
- check the size of the trap dispatch table by checking to see if the address of
- trap $A86E is the same as $AA6E.
-
- The TrapAvailable function uses the information about the size of the dispatch
- table as follows: TrapAvailable first checks to see if the trap to be tested has
- a trap number greater than the total number of traps available on the machine.
- If so, then it sets theTrap to Unimplemented before testing it against the
- Unimplemented trap.
-
- Note: The technique presented in Listing 3-1 for determining whether a
- particular trap is available differs from techniques previously supported by
- Apple. The previous method determined the size of the trap dispatch table by
- checking the machine type. This type of check should not be used for any
- purposes other than simply displaying the information, as explained in “Using
- the Gestalt Manager.”
- _______________________________________________________________________________
-
- æKY Running…in…System…Software…Version…7.0
- æC »RUNNING IN SYSTEM SOFTWARE VERSION 7.0 Compatibility Guidelines
- _______________________________________________________________________________
-
- You should keep in mind the guidelines given in the previous sections whenever
- you are writing or revising any Macintosh application. If you heed those
- guidelines, you are likely to produce applications that run reasonably well in
- all environments, including system software version 7.0. So those guidelines
- define a minimal level of conformance necessary for your applications to run in
- version 7.0. Applications that conform to the programming interfaces documented
- in Inside Macintosh and that violate none of the guidelines presented earlier in
- this chapter are called 7.0-compatible because they run in version 7.0 without
- problems.
-
- An application can be 7.0-compatible, however, without taking advantage of the
- many new features available in system software version 7.0 and without
- exhibiting an awareness that other applications may be present and may wish to
- use processor time that would otherwise go unused. Among those that do take
- advantage of such features, there are at least two levels of involvement with
- version 7.0. An application is 7.0-friendly if it takes advantage of some of the
- special features of version 7.0 when executing under that environment, but is
- still able to perform all its principal functions when executing in version 6.0.
- An application is 7.0-dependent if it requires the existence of features that
- are available only in version 7.0; it might not even run in version 6.0. Even if
- 7.0-dependent applications do execute in version 6.0, they are virtually
- guaranteed to offer far fewer features there than in version 7.0. A good example
- of a 7.0-dependent application is a multimedia application that needs to do
- real-time mixing of multiple channels of stereo sound. The Sound Manager
- included with system software version 7.0 provides support for stereo output and
- the ability to mix multiple independent channels of sampled sound; neither of
- these features is available, however, with the Sound Manager provided with
- version 6.0 or earlier.
-
- The situation is similar to deciding whether your applications should use Color
- QuickDraw. If you revise existing black-and-white drawing programs to
- incorporate color, your applications operate either with or without Color
- QuickDraw. If you introduce new applications that require Color QuickDraw, they
- simply do not run on machines that don’t support color.
-
- The rest of this section gives guidelines on what you can do to existing
- applications to make them 7.0-friendly and not simply 7.0-compatible. The
- following pages describe in overview how to
-
- • be aware that the user may have launched multiple applications
-
- • support the minimal set of required AppleEvents™
-
- • remove font size restrictions to support outline fonts
-
- • make sure that your application operates correctly with virtual memory
-
- For complete details on any of these items, see the corresponding chapter in
- this volume. For example, to learn what you need to do to support outline fonts
- in your application, see the Font Manager chapter. (The information about
- cooperating with other open applications is found in the Event Manager chapter.)
-
- _______________________________________________________________________________
-
- æKY Allowing…Multiple…Applications
- æC »Allowing Multiple Applications Compatibility Guidelines
- _______________________________________________________________________________
-
- System software version 7.0 continues the development of the Macintosh Operating
- System into a multitasking environment in which multiple applications can be
- active and must share the available system resources. The facilities provided
- with earlier versions of system software by the optional MultiFinder™ package
- are now an integral part of system software version 7.0. This means that your
- application must display a certain awareness that other applications might be
- open at the same time and competing with it for processing time, memory, control
- of communications ports, and so forth.
-
- Although most operating systems regulate the sharing of available resources by
- having the system parcel them out, the Macintosh Operating System relies on the
- willingness of foreground and background applications to share those resources
- among themselves. For example, each application must determine its own memory
- requirements by specifying a minimum memory partition size (below which that
- application does not execute) and a preferred partition size (at which the
- application executes best). The Operating System itself has very little control
- over the partition size allotted to the application, other than by limiting that
- size to the available memory. Similarly, the Operating System has very little
- control over which applications receive processing time, since the user
- ultimately decides when to bring a background application into the foreground.
- If your application holds onto the microprocessor for too long while being
- switched into the background, other applications may appear sluggish and
- unresponsive.
-
- The lesson to be learned from all this is that, in system software version 7.0,
- your application must be a good neighbor. You cannot expect the Operating System
- to force responsible behavior on your application; rather, you must ensure that
- your application can happily coexist with other open applications by following
- these guidelines:
-
- • include a 'SIZE' resource that specifies reasonable minimum and preferred
- memory partition sizes; if you occasionally need larger amounts of
- memory, use the temporary memory routines described in the Memory
- Management chapter
-
- • use WaitNextEvent instead of GetNextEvent in your main event loop to
- obtain events from the Toolbox Event Manager; this allows other
- applications to use processor time your application doesn’t need, and
- allows your application to perform operations while it is in the
- background
-
- • modify your main event loop to process suspend and resume events; this
- reduces the time it takes to switch your application into the foreground
- or background
-
- For a more complete discussion of using WaitNextEvent and processing suspend and
- resume events, see the Event Manager chapter in this volume. That chapter also
- includes a description of the multitasking environment that is standard in
- system software version 7.0.
-
- _______________________________________________________________________________
-
- æKY Supporting…Standard…AppleEvents
- æC »Supporting Standard AppleEvents Compatibility Guidelines
- _______________________________________________________________________________
-
- Possibly the most significant new feature in system software version 7.0 is
- interapplication communication (IAC), which will play an increasingly important
- role in future versions of the Macintosh Operating System. One central part of
- IAC is the addition of high-level events to those events that the Event Manager
- receives and conveys to applications. High-level events allow applications to
- communicate with one another by putting events in the event queue of the
- receiving application.
-
- Apple has defined a standard set of such high-level events, known as
- AppleEvents, that are common to all or nearly all applications. Some AppleEvents
- must be supported by an application that supports any AppleEvents; these are
- known as required AppleEvents. With a minimal amount of work, you can modify
- your main event loop so it supports the required AppleEvents. In doing so, you
- increase the level of compatibility of your application and ease the transition
- to the days when applications expect other applications to support AppleEvents.
-
- There are four main steps you need to follow to incorporate support for the
- required AppleEvents into your application:
-
- 1. Identify the AppleEvents that you want your application to support.
-
- 2. Separate code that interacts with users from code that performs operations,
- whether requested by the user or by the required AppleEvents.
-
- 3. Modify the event loop to recognize the new type of event.
-
- 4. Inform the Operating System that your application can receive and act on the
- required AppleEvents.
-
- The following four sections provide further details on each of these steps. For
- a more complete story, see the Event Manager chapter in this volume.
-
- _______________________________________________________________________________
-
- æKY Selecting…AppleEvents…to…Support
- æC »Selecting AppleEvents to Support Compatibility Guidelines
- _______________________________________________________________________________
-
- First you need to identify the AppleEvents that you want your application to
- support. To make your application 7.0-friendly, you need to support the required
- AppleEvents that Apple Computer, Inc. has already defined. Table 3-1 lists the
- required AppleEvents, together with the parameters passed to the application
- with each kind of AppleEvent.
-
- Table 3-1. Required AppleEvents
-
- Event Parameters Description
- Open Application none open an application
- Open Documents list of documents open each specified document
- Print list of documents print each specified document
- Quit none terminate and exit the application
- Setup none update application’s menu items
- Get property return value of specified property
-
- Your application should already contain code to accomplish these standard
- operations. If so, you may still need to modify that code as described in the
- next section.
- _______________________________________________________________________________
-
- æKY Isolating…User…Interface…Code
- æC »Isolating User Interface Code Compatibility Guidelines
- _______________________________________________________________________________
-
- You need to separate code that interacts with users from code that actually
- performs the operations requested by the required AppleEvents. Generally, it is
- easy to mix user interface code with code that performs some operation, so you
- need to think carefully about this step. For example, many print loops have a
- section that begins like this:
-
- IF ( PrStlDialog(thePrRecHdl) ) THEN BEGIN
- IF ( PrJobDialog(thePrRecHdl) ) THEN BEGIN
- thePrPort := PrOpenDoc(thePrRecHdl, NIL, NIL);
- IF ( PrError = noErr ) THEN BEGIN
- PrOpenPage(thePrPort, NIL);
-
- Similarly, this fragment might execute when a user chooses Open from the File
- menu:
-
- IF SFGetFile(pt, str, fileFilter, numTypes,
- typeList, dlgHook, reply) THEN BEGIN
- err := FSOpen(reply.fName, reply.vRefNum, refNum);
-
- Since an AppleEvent (and not the user) might instruct your application to open
- or print a document, the application needs to be able to perform the requested
- operation without displaying the print or file dialog boxes. A way to do this in
- version 7.0 might go like this:
-
- FUNCTION PresentPrintDialogs: Boolean;
- VAR
- thePrRecHandle: THPrint;
- BEGIN
- PresentPrintDialogs := FALSE;
- IF ( PrStlDialog(thePrRecHdl) ) THEN
- IF ( PrJobDialog(thePrRecHdl) ) THEN
- PresentPrintDialogs := TRUE;
- END;
-
- PROCEDURE PrintDocument(thePrRecHdl: THPrint);
- VAR
- thePrPort: TPPrPort;
- BEGIN
- thePrPort := PrOpenDoc(thePrRecHdl, NIL, NIL);
- IF ( PrError = noErr ) THEN BEGIN
- PrOpenPage(thePrPort,NIL);
- ...
- END;
- END;
-
- In this way, your application can respond to print requests both from the user
- and from any AppleEvents it receives.
-
- _______________________________________________________________________________
-
- æKY Modifying…the…Event…Loop
- æC »Modifying the Event Loop Compatibility Guidelines
- _______________________________________________________________________________
-
- In system software version 7.0, the Event Manager manages three classes of
- events: low-level events (which are the traditional user-initiated events like
- mouse and keyboard events), operating system event (which inform applications of
- changes in their operating status), and high-level event (which include
- AppleEvents). AppleEvents are reported to an application using a new event type
- defined by the constant kHighLevelEvent.
-
- CONST kHighLevelEvent = 23;
-
- This means that you need to add a new selector to your branch statements.
- Listing 3-2 shows a simple event loop modified to accept AppleEvents.
-
- Listing 3-2. An event loop modified to receive high-level events
-
- PROCEDURE DoEvent(event: EventRecord);
- BEGIN
- CASE event.what OF
- nullEvent:
- DoIdle;
- mouseDown:
- DoMouseDown(event);
- mouseUp:
- DoMouseUp(event);
- keyDown, autoKey:
- DoKeyDown(event);
- activateEvt:
- DoActivate(event);
- updateEvt:
- DoUpdate(event);
- kOSEvent:
- DoOSEvent(event);
- kHighLevelEvent:
- DoHighLevelEvent(event);
- END;
- END; {DoEvent}
-
- At this point, you need to provide the DoHighLevelEvent routine to handle the
- AppleEvent (or other high-level event). Once you’ve separated the relevant
- user-interface part of your code, modified your event loop, and added a
- procedure that accepts high-level events, all you need to do is write a bit of
- code that knows how to look at AppleEvents and then calls the correct operation.
-
- _______________________________________________________________________________
-
- æKY Indicating…an…Application…Is…AppleEvent-Aware
- æC »Indicating an Application Is AppleEvent-Aware Compatibility Guidelines
- _______________________________________________________________________________
-
- The final thing you need to do is inform the Operating System that your
- application is able to receive and process AppleEvents. To accomplish this, you
- need to modify your application’s 'SIZE' resource, as explained in the Event
- Manager chapter.
-
- _______________________________________________________________________________
-
- æKY Removing…Font…Size…Restrictions
- æC »Removing Font Size Restrictions Compatibility Guidelines
- _______________________________________________________________________________
-
- System software version 7.0 introduces outline fonts, known as TrueType™. An
- outline font can be printed or displayed at any point size without the jagged
- appearance of some bitmapped fonts. A 7.0-friendly application should allow its
- users to take advantage of this improvement. Minimally, this means that users
- should be able to ask for any point size up to 32,768. Many applications now let
- users specify font sizes up to 127 point, but you should remove even this
- limitation when running in version 7.0. In addition, your application should
- allow users to increment or decrement the font size by 1 point.
-
- You can use the IsOutline routine, documented in the Font Manager chapter in
- this volume, to see if a particular font is an outline font. If it is, you might
- wish to indicate that fact in your font size menu. For example, suppose that
- your Size menu for a particular bitmapped font looks like the one in Figure 3-1.
-
- ø 3.1 Size menu for a bitmapped font
-
- To provide a visual indication that the selected font is an outline font that
- looks good at any size, you might change the menu to look like the one in Figure
- 3-2. One way to do this is by outlining all available sizes, as well as the
- Other item.
-
- ø 3.2 Size menu for an outline font
-
- The User Interface Guidelines chapter contains additional suggestions on
- incorporating outline fonts into your application.
-
- _______________________________________________________________________________
-
- æKY Operating…With…Virtual…Memory
- æC »Operating With Virtual Memory Compatibility Guidelines
- _______________________________________________________________________________
-
- System software version 7.0 supports virtual memory, a memory management scheme
- that extends the logical address space of the machine by using part of the
- available secondary storage (usually, a hard disk) to store parts of memory that
- are not currently in use. When virtual memory is present, the perceived amount
- of RAM can extend up to 14 megabytes on systems with 24-bit ROMs and up to 4
- gigabytes on systems with 32-bit clean ROMs. Since the Operating System has more
- addressable memory, your applications can ask for and receive larger blocks of
- memory than they would if virtual memory were not available.
-
- Virtual memory is available only on machines equipped with a memory management
- unit (MMU). Currently, these machines include 68030-based machines (where the
- MMU is built into the CPU) as well as 68020-based machines that contain the
- 68851 Paged Memory Management Unit. You can use the Gestalt function to
- determine whether virtual memory is installed. If it is, you may need to
- exercise caution to ensure that the normally invisible operation of virtual
- memory does not adversely affect the execution of your application. Applications
- that might need to be concerned with virtual memory include those that have
- critical timing requirements, execute code at interrupt time, or perform
- debugging operations.
-
- Note: The vast majority of applications do not need to know whether virtual
- memory is installed.
-
- One type of application that might need to know if virtual memory is operating
- is a multimedia application that manages very large images or incorporates many
- sounds into its presentations. Imagine that such an application wants to display
- a large number of intricate color images in rapid succession, and that some of
- those images are as large as a megabyte each. If virtual memory is operating, it
- is very likely that parts of those images are on disk when they need to be
- displayed. This means that in the middle of drawing a picture, the system has to
- stop long enough to read those parts of the picture off the disk. The result is
- that a noticeable delay may occur, which may be unacceptable.
-
- In a case like this, you can use routines that lock the appropriate data into
- RAM, so that displaying the image requires no disk access. These routines are
- fully documented in the Memory Management chapter later in this volume. Other
- software that may need to know about those routines includes drivers, interrupt
- code, and debugging applications.
-
- _______________________________________________________________________________
-
- æKY Localizing…Macintosh…Programs
- æC »LOCALIZING MACINTOSH PROGRAMS Compatibility Guidelines
- _______________________________________________________________________________
-
- Localization is the process of adapting an application to a specific language
- and country. By planning ahead and making localization relatively painless,
- you’ll ensure that international markets are available for your product in the
- future. This section provides a brief overview of what you need to do to make it
- easy to localize your application. For the complete account of writing software
- that is compatible with Macintosh computers throughout the world, you should
- read the TextEdit chapter and the Worldwide Software Overview later in this
- volume. You should also consult the “Developing Worldwide Software” section in
- the User Interface Guidelines chapter of this volume.
-
- _______________________________________________________________________________
-
- æKY General…Guidelines…for…Compatibility
- æC »General Guidelines Compatibility Guidelines
- _______________________________________________________________________________
-
- The key to easy localization is to store country-dependent information used by
- your application as resources (rather than within the application’s code). Text
- seen by the user can then be translated without modifying the code. In addition,
- storing such information in resources means that your application can be adapted
- for a different country simply by substituting the appropriate resources. Make
- sure that at least the following kinds of information are stored in resources:
-
- • all text, including special characters and delimiters
-
- • menus and keyboard equivalents for menu commands (if available)
-
- • character, word, phrase, and text translation tables
-
- • address formats, including zip codes and phone numbers
-
- When you create resources for your applications, remember the following key
- points:
-
- • text needs room to grow (up, down, and sideways)
-
- • translated text is often 50 percent larger than the U.S. English text
-
- • diacritical marks, widely used outside the United States, may extend up
- to the ascent line
-
- • some system fonts contain characters that extend to both the ascent and
- descent lines
-
- • potential grammar problems may arise from error messages, “natural”
- programming language structures, and so forth
-
- • text location within a window should be easy to change
- _______________________________________________________________________________
-
- æKY Other…Localization…Tools
- æC »Other Localization Tools Compatibility Guidelines
- _______________________________________________________________________________
-
- In addition to these general guidelines, you need to be aware of a host of other
- localization issues, such as differences in script systems and measurement
- systems. System software version 7.0 contains updated versions of several tools
- that you can use to facilitate localization of your applications—TextEdit, the
- International Utilities Package, and the Script Manager.
-
- Perhaps the most important localization tool is the Script Manager, which
- contains routines that allow your application to function correctly with
- non-Roman scripts (or writing systems). The Script Manager furnishes a standard
- interface that allows installation of different script systems, maintains global
- data structures, supports switching keyboards between different scripts, and
- provides a central dispatcher that gives your application access to script
- systems. It also contains utilities for text processing and parsing, which are
- useful for applications that do a lot of text manipulation. The Script Manager
- provides easy ways to translate your application into another writing system and
- to coordinate with the International Utilities Package.
-
- The International Utilities Package provides routines for dealing with sorting,
- currency, measurement systems, and date and time formatting. These tend to vary
- in some degree from script to script, language to language, and country to
- country, and your application should take advantage of the Macintosh Operating
- System’s ability to present this information in the correct format. It is
- important that you use the routines in this package rather than the System
- Utility routines contained in ROM; the ROM routines are not as accurate and
- (because they are used by the File Manager) cannot be localized for different
- countries.
-
- TextEdit provides routines that handle basic text formatting and editing
- capabilities, such as inserting new text or scrolling text within a window. The
- version of TextEdit included in system software version 7.0 contains new
- features that allow it to work with different scripts. For example, TextEdit 3.0
- takes advantage of the Script Manager’s handling of double-byte characters to
- display scripts (such as Kanji) with improved accuracy and consistency.
-
- For more information about the enhanced versions of TextEdit, see the TextEdit
- chapter in this volume. For complete information on both the International
- Utilities Package and the Script Manager, see the Worldwide Software Overview
- chapter.
-
- _______________________________________________________________________________
-
- æKY Running…Macintosh…Programs…Under…A/UX
- æC »RUNNING MACINTOSH PROGRAMS UNDER A/UX Compatibility Guidelines
- _______________________________________________________________________________
-
- A/UX is Apple’s version of the UNIX operating system, which provides a
- multitasking and multiuser software execution environment. One of the most
- distinctive features of A/UX in comparison with other implementations of the
- UNIX operating system is its ability to run conforming Macintosh applications.
- Within limits described later in this section, applications developed for the
- Macintosh Operating System using the standard Macintosh User Interface Toolbox
- routines will execute under A/UX. Figure 3-3 shows a typical screen under A/UX.
-
- ø 3.3 The Macintosh User Interface Under A/UX
-
- The ability to run Macintosh applications under A/UX is provided by enhancements
- to the A/UX kernel and by a library of functions known as the A/UX Toolbox. The
- A/UX Toolbox is a library of routines that enables a program running under A/UX
- to call Macintosh Toolbox routines and native Macintosh Operating System
- routines. The A/UX Toolbox provides a bridge between the Macintosh and A/UX
- environments, giving you two kinds of code compatibility:
-
- • You can execute Macintosh binary code (applications compiled in the
- Macintosh environment) under A/UX, within the current limitations of the
- A/UX Toolbox.
-
- • You can write common source code that can be separately built (that is,
- compiled and linked) into executable code for both environments.
-
- The A/UX Toolbox operates transparently to the user and to the application
- developer. This means that (subject once again to qualifications detailed later)
- your applications developed for the Macintosh Operating System should execute
- under the A/UX operating system.
-
- The version of A/UX currently available is A/UX Release 2.0, which greatly
- extends the capabilities of earlier versions. Release 2.0 supports more managers
- and drivers than previous versions, thereby increasing the level of
- compatibility with Macintosh applications. There is now transparent access to
- Macintosh file systems from within A/UX, so users no longer have to transfer
- files between the two systems manually.
-
- This section briefly explains how the A/UX Toolbox works and then provides
- details on writing Macintosh applications that execute under the A/UX operating
- system. A/UX Release 2.0 provides such a high level of compatibility with
- Macintosh applications that your existing applications may very well run under
- A/UX with no changes whatsoever. To run successfully under A/UX Release 2.0,
- your application should
-
- • be compatible with MultiFinder
-
- • be 32-bit clean (that is, operate in an environment where all 32 bits of
- a handle or pointer are significant in determining memory addresses)
-
- • use the Gestalt Manager to determine whether the appropriate versions of
- managers are present in the current operating environment
-
- • avoid reading or writing low-memory global variables
-
- In general, applications that conform to the interfaces documented in Inside
- Macintosh, are MultiFinder-aware, do not rely on low-memory global variables,
- and heed the various guidelines presented in “About Compatibility” should
- operate under A/UX.
-
- _______________________________________________________________________________
-
- æKY How…the…A/UX…Toolbox…Works
- æC »How the A/UX Toolbox Works Compatibility Guidelines
- _______________________________________________________________________________
-
- The primary function of the A/UX Toolbox is to make available to programs
- running under A/UX the standard Macintosh support code described in Inside
- Macintosh. Most of the support code consists of routines built into the
- Macintosh ROM.
-
- The ROM routines fall into two categories, User Interface Toolbox routines and
- Macintosh Operating System routines. The A/UX Toolbox uses one of two strategies
- for supporting a Macintosh ROM call, depending on whether the call is to the
- User Interface Toolbox or to the native Macintosh Operating System.
-
- When an A/UX Toolbox application calls one of the Macintosh User Interface
- Toolbox routines, the A/UX Toolbox intercepts the call and, if necessary,
- translates the parameters into a form usable by the ROM. After the A/UX Toolbox
- performs the translation, it invokes the ROM code that would be used in the
- native Macintosh environment.
-
- When an A/UX Toolbox application calls one of the Macintosh Operating System
- routines, the A/UX Toolbox diverts the call to a substitute routine in its own
- library. The A/UX Toolbox Operating System routines call the standard A/UX
- libraries to perform the A/UX equivalents of the Macintosh Operating System
- functions. The Macintosh Operating System ROM code is never used under A/UX.
- Note that some of the built-in User Interface Toolbox routines generate calls to
- the Macintosh Operating System routines; these calls are also intercepted by the
- A/UX Toolbox and diverted to routines in its own library.
-
- Figure 3-4 illustrates how the two elements of the A/UX Toolbox library interact
- with the application and the ROM code.
-
- ø 3.4 Interactions among applications, the A/UX Toolbox, and ROM code
-
- _______________________________________________________________________________
-
- æKY Using…the…A/UX…Toolbox
- æC »Using the A/UX Toolbox Compatibility Guidelines
- _______________________________________________________________________________
-
- The primary limitation on Macintosh applications running under A/UX is that the
- A/UX Toolbox does not currently support all managers and drivers. Table 3-2
- summarizes the status of various ROM libraries in A/UX Release 2.0.
-
- Table 3-2. Status of User Interface Toolbox and Macintosh Operating System
- libraries in the A/UX Toolbox
-
- ROM Library Implementation
-
- Alias Manager None
- Apple Desktop Bus None
- Binary-Decimal Conversion Package Full
- Color Manager Full
- Color Picker Package Full
- Color QuickDraw Full
- Control Manager Full
- Database Access Manager None
- Deferred Task Manager None
- Desk Manager Full
- Device Manager Full
- Dialog Manager Full
- Disk Driver Full
- Disk Initialization Package Full
- Edition Manager None
- Event Manager, Operating System Partial
- Event Manager, Toolbox Full*
- File Manager Full
- Floating Point Arithmetic
- and Transcendental Functions Packages Full*
- Font Manager Full
- Gestalt Manager Full
- Help Manager None
- International Utilities Package Full
- List Manager Package Full
- Memory Manager Full
- Menu Manager Full
- Notification Manager Full
- Package Manager Full
- Palette Manager Full
- Power Manager None
- PPC Toolbox None
- Printing Manager Full
- QuickDraw Full
- Resource Manager Full
- Scrap Manager Full
- Script Manager Full
- SCSI Manager None
- Segment Loader Partial
- Serial Driver Full
- Shutdown Manager Full*
- Slot Manager Full
- Sound Manager Full
- Startup Manager Full
- Standard File Package Full
- System Error Handler Full*
- TextEdit Full
- Time Manager Full*
- Utilities, Operating System Partial
- Utilities, Toolbox Full
- Vertical Retrace Manager Partial
- Window Manager Full
-
- Note that when A/UX Release 2.0 implements a particular manager or driver, the
- version of that manager or driver may not be the same as the version available
- in the Macintosh Operating System. This means that, whenever possible, you
- should use Gestalt to check for the existence of the particular features your
- application needs. In managers or drivers marked with an asterisk (*), all calls
- are implemented under A/UX, but the behavior is not identical to that in the
- Macintosh Operating System. See the publication A/UX Toolbox: Macintosh ROM
- Interface for complete details on the implementation of these managers and
- drivers.
-
- _______________________________________________________________________________
-
- æKY A/UX…Compatibility…Guidelines
- æC »A/UX Compatibility Guidelines Compatibility Guidelines
- _______________________________________________________________________________
-
- The A/UX Toolbox has been designed to allow as many Macintosh applications as
- possible to execute under the A/UX operating system. Because of profound
- differences between the two environments, however, it is possible that some
- applications may not execute correctly under A/UX. By following these
- guidelines, you can help ensure that your Macintosh applications run under A/UX.
-
- • Make certain that your application is MultiFinder-friendly. MultiFinder
- is a standard part of A/UX Release 2.0, just as it is in system software
- version 7.0. Your application should include a 'SIZE' resource and call
- WaitNextEvent in its main event loop. Note that the version of
- MultiFinder included with A/UX Release 2.0 is functionally equivalent to
- the version of MultiFinder released with system software version 6.0.5,
- but has been customized for use under A/UX.
-
- • Always use the available managers and drivers to manipulate hardware
- devices. In the Macintosh Operating System, individual processes and the
- various libraries can have much more control over the system than under
- A/UX, where the kernel manages all interaction between processes and the
- underlying hardware. In particular, do not attempt to read data from or
- write data to any of the memory-mapped hardware available on a Macintosh
- computer.
-
- • Avoid relying on any of the low-memory global variables. Not all of them
- are available under A/UX.
-
- • Make certain that your application is 32-bit clean (that is, it operates
- in an environment where all 32 bits of a handle or pointer are
- significant in determining memory addresses).
-
- • Use the Gestalt Manager to determine which versions of managers and
- drivers are present in the current operating environment before relying
- on features that are not common to all released versions. Generally, the
- versions of managers available under A/UX Release 2.0 are the same as
- those versions included in Macintosh system software version 6.0.5.
-
- Finally, your application should conform to the programming interfaces described
- in Inside Macintosh and should follow the basic compatibility guidelines
- presented in “About Compatibility” earlier in this chapter.
-
- _______________________________________________________________________________
-
- æKY About…the…Gestalt…Manager
- æC »ABOUT THE GESTALT MANAGER Compatibility Guidelines
- _______________________________________________________________________________
-
- The Macintosh family of computers has grown tremendously in the past several
- years, and it is likely to grow in the future. Macintosh software now runs on a
- number of different processors, some of which are accompanied by floating-point
- coprocessors or memory management units. In addition, the installed versions of
- the system software, drivers, and QuickDraw routines may vary from machine to
- machine. To ensure that your applications are maximally compatible with existing
- and future versions of the Macintosh, you should keep references to specific
- software and hardware features to a minimum. In general, applications should
- communicate with the system software and hardware through the available managers
- and device drivers. If, however, it is necessary or useful for your applications
- to take advantage of software or hardware components that may not be present on
- all Macintosh computers, then you need some method of determining whether those
- components are available. The Gestalt Manager serves this need by allowing you
- to get information about the operating environment in a simple and efficient
- manner.
-
- System software version 7.0 is a major software release that affects the entire
- Macintosh line of computers, spanning different CPUs, different versions of ROM,
- and machines with a variety of hardware and software configurations. Version 7.0
- introduces several new managers and makes significant changes to many existing
- managers. To take advantage of new version 7.0 features, and to run on as many
- machines as possible, it is more important than ever before to determine the
- software and hardware components available in a particular operating
- environment.
-
- To deal with this increasingly complex situation, system software version 7.0
- includes the Gestalt Manager. This manager includes the Gestalt function, which
- is a replacement for both the SysEnvirons function and the Environs procedure.
- The Gestalt function gives applications the ability to determine information
- about a large number of machine-dependent features. You can use the Gestalt
- function to find the following sorts of information about the hardware
- configuration and operating environment of the machine your application is
- executing on:
-
- • the type of machine
- • the version of the System file currently running
- • the type of CPU
- • the type of keyboard attached to the machine
- • the type of floating-point processing unit (FPU), if any
- • the type of memory management unit (MMU), if any
- • the size of available RAM
- • the amount of available virtual memory
- • the versions of various drivers and managers
- • the features of various drivers and managers
- • the version of QuickDraw currently present
- • whether the A/UX operating system is running or not
-
- How your application uses the resulting information depends on what your
- application needs to accomplish. For example, in a case where critical hardware
- features are not available, your application might display an alert box to
- notify the user that the required hardware is missing and then terminate. Or, if
- your application has determined that Color QuickDraw is available, it could
- execute alternate code to take advantage of the expanded capabilities of that
- software.
-
- Associated with the Gestalt function are two other functions—one that allows an
- application to register new features with Gestalt and another that allows an
- application to change the function used by Gestalt to retrieve a particular
- piece of information. These two functions make it easy for your application to
- announce its presence to other applications, in case they wish to alter their
- actions in view of the presence of your application. For example, a macro
- utility that intercepts sequences of keyboard presses and translates them into
- other sequences can register itself with Gestalt at system initialization time;
- afterward, other applications can call Gestalt to determine if that utility is
- present. In this way, Gestalt can act as a central clearinghouse for information
- on the available hardware and software features of the operating environment,
- including any third-party applications that register themselves with Gestalt.
- Gestalt therefore provides a further means of cooperation and awareness among
- applications executing in the version 7.0 environment.
-
- Although the Gestalt function can provide your application with most of the
- basic information it needs about particular software or hardware features, you
- may still need to call other routines to determine more specific features. For
- example, if you need to determine the resolution of the Macintosh screen, you
- can use the Toolbox Utility procedure ScreenRes. (See the Toolbox Utilities
- chapter of Inside Macintosh, Volume I, for a description of this procedure.)
- The Gestalt function replaces both the Environs procedure and the current
- implementation of the SysEnvirons function as the standard means of determining
- specific aspects of the operating environment. The Gestalt Manager is simpler to
- use and provides more information than either of those routines. Applications
- that use SysEnvirons still execute correctly in system software version 7.0 (the
- SysEnvirons function calls the Gestalt function).
-
- Use of the Environs procedure is no longer recommended, because it encourages
- you to think in terms of ROM versions, not in term of features that may be
- available. The Gestalt Manager can also provide information such as ROM version
- and size, but you should not write applications that infer the presence of
- particular software or hardware features on the basis of that information. When
- you need to know whether a particular feature is present, you should request
- information about it directly, using the appropriate Gestalt selector.
-
- Although you can still call the SysEnvirons function, the Gestalt Manager is
- simpler and more efficient, and is the recommended way to get information about
- the operating environment. SysEnvirons returns a pointer to a system environment
- record containing nine different pieces of information. Gestalt returns only the
- information requested by use of a specific selector code parameter. In most
- cases, your application really needs only a part of what is contained in the
- system environment record. With Gestalt, your application can request only the
- information it needs.
-
- _______________________________________________________________________________
-
- æKY Using…the…Gestalt…Manager
- æC »USING THE GESTALT MANAGER Compatibility Guidelines
- _______________________________________________________________________________
-
- The Gestalt Manager includes three functions—Gestalt, NewGestalt, and
- ReplaceGestalt. You can use the Gestalt function to obtain information about
- software or hardware components available on the current machine. You can use
- NewGestalt to register new software modules (such as drivers and patches) with
- the Operating System. Use ReplaceGestalt to replace the function associated with
- a particular selector code by some other function.
-
- Note: Most applications do not need to use either NewGestalt or ReplaceGestalt.
-
- _______________________________________________________________________________
-
- æKY Determining…Features…of…the…Operating…Environment
- æC »Determining Features of the Operating Environment Compatibility Guidelines
- _______________________________________________________________________________
-
- When your application needs information about a specific software or hardware
- feature that can be provided by the Gestalt function, your application can pass
- Gestalt a selector code (or selector) as one of the parameters. The selector
- code is simply an indication of what information your application currently
- needs. There are two types of selector codes—predefined selector codes that are
- always recognized by Gestalt, and application-defined selector codes that
- applications may register with Gestalt by calling the NewGestalt function.
-
- If Gestalt can determine the requested information, it returns that information
- in its second parameter, known as the response parameter. If Gestalt cannot
- obtain the desired information, it returns a result code indicating the cause of
- the error, and the value of the response parameter is undefined. You should
- always check the result code returned by Gestalt to make sure that the response
- parameter contains meaningful information.
-
- Note: When passed one of the predefined selector codes, Gestalt does not move
- or purge memory and therefore may be called at any time, even at interrupt time.
- However, selector functions associated with application-defined selector codes
- may move or purge memory, and applications can alter Gestalt’s predefined
- selector functions. As a result, it is safest to assume that Gestalt might
- always move or purge memory. The NewGestalt function may move memory and should
- not be called at interrupt time.
-
- There are two types of predefined selector codes: codes that return information
- that your application can use to guide its actions (known as environmental
- selectors), and codes that provide information only and should never be used as
- an indication of some feature’s existence (known as informational selectors).
-
- It is particularly important that you understand the difference between
- environmental and informational selectors. The response returned by Gestalt when
- it is passed an informational selector is for your (or the user’s) edification
- only and should never be used by your application as a means of determining
- whether some specific software or hardware feature is available. For example,
- you can use Gestalt to determine the version of the ROM installed on a
- particular machine, but you should never use this information to guide any of
- your application’s actions. Routines you expect to be in ROM may actually be in
- RAM; hence, you cannot determine that some routine usually found in ROM is not
- present simply by looking at the ROM version. Also, routines contained in ROM
- may have been patched by the system at startup time, in which case the system
- might not have the features that you think it has on the basis of the reported
- ROM version. Similar remarks apply to other informational selectors such as ROM
- size, machine type, and System file version.
-
- You can use the following environmental selectors to determine information about
- the operating environment.
-
- CONST
- gestaltVersion = 'vers'; {Gestalt version}
- gestaltAddressingModeAttr = 'addr'; {addressing mode attributes}
- gestaltAliasMgrAttr = 'alis'; {Alias Mgr attributes}
- gestaltAppleTalkVersion = 'atlk'; {AppleTalk version}
- gestaltAUXVersion = 'a/ux'; {A/UX version if present}
- gestaltCTBVersion = 'ctbv'; {Comm Toolbox version}
- gestaltDBAccessMgrAttr = 'dbac'; {Database Access Mgr attrs}
- gestaltEditionMgrAttr = 'edtn'; {Edition Mgr attributes}
- gestaltAppleEventsAttr = 'evnt'; {AppleEvents attributes}
- gestaltFolderMgrAttr = 'fold'; {Folder Mgr attributes}
- gestaltFontMgrAttr = 'font'; {Font Mgr attributes}
- gestaltFPUType = 'fpu '; {FPU type}
- gestaltHardwareAttr = 'hdwr'; {hardware attributes}
- gestaltHelpMgrAttr = 'help'; {Help Mgr attributes}
- gestaltKeyboardType = 'kbd '; {keyboard type}
- gestaltLowMemorySize = 'lmem'; {low-memory area size}
- gestaltLogicalRAMSize = 'lram'; {logical RAM size}
- gestaltMiscAttr = 'misc'; {miscellaneous attributes}
- gestaltMMUType = 'mmu '; {MMU type}
- gestaltNotificationMgrAttr = 'nmgr'; {Notification Mgr attrs}
- gestaltOSAttr = 'os '; {O/S attributes}
- gestaltLogicalPageSize = 'pgsz'; {logical page size}
- gestaltPPCToolboxAttr = 'ppc '; {PPC Toolbox attributes}
- gestaltPowerMgrAttr = 'powr'; {Power Mgr attributes}
- gestaltProcessorType = 'proc'; {processor type}
- gestaltParityAttr = 'prty'; {parity attributes}
- gestaltQuickdrawVersion = 'qd '; {QuickDraw version}
- gestaltPhysicalRAMSize = 'ram '; {physical RAM size}
- gestaltResourceMgrAttr = 'rsrc'; {Resource Mgr attributes}
- gestaltScriptMgrVersion = 'scri'; {Script Mgr version}
- gestaltScriptCount = 'scr#'; {# of active script systems}
- gestaltSoundAttr = 'snd '; {sound attributes}
- gestaltTextEditVersion = 'te '; {TextEdit version}
- gestaltTimeMgrVersion = 'tmgr'; {Time Mgr version}
- gestaltVMAttr = 'vm '; {virtual memory attributes}
-
- The following informational selectors are provided for informational purposes
- only. You can display the information returned when using these selectors, but
- you should never use this information as an indication of what software features
- or hardware may be available.
-
- CONST
- gestaltMachineType = 'mach'; {machine type}
- gestaltROMSize = 'rom '; {ROM size}
- gestaltROMVersion = 'romv'; {ROM version}
- gestaltSystemVersion = 'sysv'; {System file version}
-
- “Interpreting Gestalt Responses” later in this chapter provides the exact
- meaning of each of these selectors and of the values returned by Gestalt in each
- case.
-
- _______________________________________________________________________________
-
- æKY Determining…Whether…Gestalt…Is…Available
- æC »Determining Whether Gestalt Is Available Compatibility Guidelines
- _______________________________________________________________________________
-
- Because the Gestalt Manager currently exists only in system software versions
- 6.0.4 and later (and in ROM on the Macintosh IIci and Portable), you should make
- certain that it is actually available before attempting to call it. You can do
- this by using the TrapAvailable function defined above in “Determining Whether a
- Trap Is Available.” Listing 3-3 uses that function to determine whether the
- Gestalt Manager is available.
-
- Note: If you are using the MPW development system version 3.2 or later, then
- you do not need to perform this check, because that system provides glue
- routines that allow you to call Gestalt even if it is not in ROM or in the
- System file. However, if you are programming in assembly language, this glue is
- not provided (and you still need to check that Gestalt is available before
- calling it).
-
- Listing 3-3. Determining whether Gestalt is available
-
- FUNCTION GestaltAvailable: Boolean;
- CONST
- _Gestalt = $A1AD;
- BEGIN
- GestaltAvailable := TrapAvailable(_Gestalt);
- END;
-
- If you need to know at several different places in your application whether
- Gestalt is available, it may be more efficient to define a global Boolean
- variable that you can test before calling Gestalt. Listing 3-4 illustrates how
- to do this. Once again, this code uses the TrapAvailable function defined
- earlier.
-
- Listing 3-4. Using Gestalt to determine the Time Manager version
-
- VAR
- hasGestalt: Boolean; {true if Gestalt is implemented}
-
- hasGestalt := TrapAvailable(_Gestalt);
- .
- .
- .
-
- IF hasGestalt THEN BEGIN
- myErr := Gestalt(gestaltTimeMgrVersion, myFeature);
- IF myErr <> noErr THEN
- DoError(myErr);
- END;
-
- This sample code returns (in the myFeature variable) the version of the Time
- Manager available on the current machine. Before using that information,
- however, you should test the result code to make sure that Gestalt was able to
- determine the requested information.
-
- _______________________________________________________________________________
-
- æKY Interpreting…Gestalt…Responses
- æC »Interpreting Gestalt Responses Compatibility Guidelines
- _______________________________________________________________________________
-
- When your application calls Gestalt to get information about the operating
- environment, the meaning of the value that Gestalt returns in the response
- parameter depends on the selector code with which it was called. For example, a
- call to Gestalt using the gestaltTimeMgrVersion selector returns a version code
- in the low-order byte of the response parameter. In this case, a returned value
- of 3 indicates that the extended Time Manager is available.
-
- In almost all cases, the last few characters in the selector’s symbolic name
- form a suffix that indicates what type of value you can expect Gestalt to
- return. For example, if the final characters in a Gestalt selector are Addr,
- then Gestalt returns an address in the response parameter. The following list
- shows the meaningful suffixes.
-
- Suffix Meaning
-
- Addr The returned value is an address.
-
- Attr The returned value is a range of bits, the meaning of which must be
- determined by comparison with a list of constants. Note that bit 0 is
- the least significant bit of the long word.
-
- Count The returned value is a number indicating how many of the indicated type
- of item exist.
-
- Size The returned value is a size. Sizes reported by Gestalt are usually in
- bytes.
-
- Type The returned value is an index describing a particular type of feature.
-
- Version The returned value is a version number. Implied decimal points may
- separate digits of the returned value. For example, a value of $0603
- returned in response to the gestaltSystemVersion selector indicates
- that system software version 6.0.3 is present.
-
- Selectors that have the suffix Attr deserve special attention; they cause
- Gestalt to return a bit field that your application must interpret in order to
- determine whether a desired feature is present. For example, the gestaltOSAttr
- selector requests information about a number of Operating System features. To
- determine whether a particular Operating System feature is available, you need
- to read the appropriate bit in the response parameter, as Listing 3-5
- illustrates.
-
- Listing 3-5. Interpreting a bit field response
-
- VAR
- myBit: Integer;
- myFeature: LongInt;
- myErr: Integer;
-
- IF hasGestalt THEN BEGIN
- myErr := Gestalt(gestaltOSAttr, myFeature);
- IF myErr <> noErr THEN
- DoError(myErr)
- ELSE BEGIN
- myBit := gestaltTempMemSupport;
- IF BTst(myFeature, 31-myBit) = TRUE THEN
- WriteLn('temporary memory support available')
- ELSE
- WriteLn('temporary memory support not available');
- END;
- END;
-
- This code uses the MPW function BTst to determine if the appropriate bit in
- Gestalt’s response is equal to 1. Your development system may have other ways of
- testing the appropriate bit.
-
- _______________________________________________________________________________
-
- æKY Interpreting…Responses…to…Environmental…Selectors
- æC »Interpreting Responses to Environmental Selectors Compatibility Guidelines
- _______________________________________________________________________________
-
- Gestalt returns one of the following responses when passed a predefined
- environmental selector.
-
- gestaltVersion
-
- Returns the version of Gestalt. The current version is 1, corresponding to a
- returned value of $0001.
-
- gestaltAddressingModeAttr
-
- Returns information about the current addressing.
-
- CONST
- gestalt32BitAddressing = 0;
- gestalt32BitSysZone = 1;
- gestalt32BitCapable = 2;
-
- The gestalt32BitAddressing attribute indicates that the machine started up with
- 32-bit addressing. The gestalt32BitSysZone attribute indicates that the system
- heap has 32-bit clean block headers (regardless of the type of addressing the
- machine started up in). See the Memory Management chapter for more information
- about 32-bit addressing.
-
- gestaltAliasMgrAttr
-
- Returns information about the Alias Manager.
-
- CONST
- gestaltAliasMgrPresent = 0;
-
- gestaltAppleTalkVersion
-
- Returns the version number of the AppleTalk driver currently installed. In
- particular, it returns the version number of the MPP driver. The version number
- is placed into the low-order byte of the result, so you should ignore the three
- high-order bytes of the result. If an AppleTalk driver is not currently open,
- the response parameter is 0. The driver will not be opened until the user
- requests a network service (such as Chooser).
-
- gestaltAUXVersion
-
- Returns the version of A/UX if it is currently executing. The result is placed
- into the lower word of the response parameter. If A/UX is not executing, Gestalt
- returns gestaltUnknownErr.
-
- gestaltCTBVersion
-
- Returns the version number of the Communications Toolbox.
-
- gestaltDBAccessMgrAttr
-
- Returns information about the Database Access Manager.
-
- CONST
- gestaltDBAccessMgrPresent = 0;
-
- gestaltEditionMgrAttr
-
- Returns information about the Edition Manager.
-
- CONST
- gestaltEditionMgrPresent = 0;
-
- gestaltAppleEventsAttr
-
- Returns information about AppleEvents.
-
- CONST
- gestaltAppleEventsPresent = 0;
-
- gestaltFolderMgrAttr
-
- Returns information about the Folder Manager.
-
- CONST
- gestaltFolderMgrPresent = 0;
-
- gestaltFontMgrAttr
-
- Returns information about the Font Manager.
-
- CONST
- gestaltOutlineFonts = 0;
-
- gestaltFPUType
-
- Returns a value that indicates the type of floating-point coprocessor currently
- installed, if any.
-
- CONST
- gestaltNoFPU = 0;
- gestalt68881 = 1;
- gestalt68882 = 2;
-
- gestaltHardwareAttr
-
- Returns information about the hardware configuration of the machine.
-
- CONST
- gestaltHasVIA1 = 0;
- gestaltHasVIA2 = 1;
- gestaltHasASC = 3;
- gestaltHasSCC = 4;
- gestaltHasSCSI = 7;
-
- gestaltHelpMgrAttr
-
- Returns information about the Help Manager.
-
- CONST
- gestaltHelpMgrPresent = 0;
-
- gestaltKeyboardType
-
- Returns a value that indicates the type of keyboard that is currently attached
- to the system.
-
- CONST
- gestaltMacKbd = 1;
- gestaltMacAndPad = 2;
- gestaltMacPlusKbd = 3;
- gestaltExtADBKbd = 4;
- gestaltStdADBKbd = 5;
- gestaltPrtblADBKbd = 6;
- gestaltPrtblISOKbd = 7;
- gestaltStdISOADBKbd = 8;
- gestaltExtISOADBKbd = 9;
-
- If the Apple Desktop Bus™ is in use, there may be multiple keyboards or other
- ADB devices attached to the machine. Gestalt returns the type of the keyboard on
- which the last keystroke occurred.
-
- gestaltLowMemorySize
-
- Returns the size (in bytes) of the low-memory area. The low-memory area is used
- for vectors, global variables, and dispatch tables.
-
- gestaltLogicalRAMSize
-
- Returns the amount of logical memory available. This value is the same as that
- returned by gestaltPhysicalRAMSize when virtual memory is not installed. On some
- machines, however, this value might be less than the value returned by
- gestaltPhysicalRAMSize, because some RAM may be used by the video display and
- the Operating System.
-
- gestaltMiscAttr
-
- Returns information about miscellaneous pieces of the Operating System or
- hardware configuration. Currently only one value is returned.
-
- CONST
- gestaltScrollingThrottle = 0;
-
- gestaltMMUType
-
- Returns a value that indicates the type of MMU currently installed, if any.
-
- CONST
-
- gestaltNoMMU = 0;
- gestaltAMU = 1;
- gestalt68851 = 2;
- gestalt68030MMU = 3;
-
- gestaltNotificationMgrAttr
-
- Returns information about the Notification Manager.
-
- CONST
- gestaltNotificationMgrPresent = 0;
-
- gestaltOSAttr
-
- Returns general information about the Operating System, such as whether
- temporary memory handles are real handles. The low-order bits of the response
- parameter are interpreted as bit flags. A flag is set to 1 to indicate that the
- corresponding feature is available. Currently the following bits are
- significant:
-
- CONST
- gestaltSysZoneGrowable = 0;
- gestaltLaunchCanReturn = 1;
- gestaltLaunchFullFileSpec = 2;
- gestaltLaunchControl = 3;
- gestaltTempMemSupport = 4;
- gestaltRealTempMemory = 5;
- gestaltTempMemTracked = 6;
- gestaltIPCSupport = 7;
- gestaltSysDebuggerSupport = 8;
-
- See the Memory Management chapter in this volume for a full explanation of the
- temporary memory features and the Process Management chapter for a full
- explanation of the launch control features.
-
- gestaltLogicalPageSize
-
- Returns the logical page size. This value is an unknown on 68000-based machines,
- since such machines do not have logical pages. On those machines, Gestalt
- returns an error.
-
- gestaltPowerMgrAttr
-
- Returns information about the Power Manager, if present.
-
- CONST
- gestaltPMgrExists = 0;
- gestaltPMgrCPUIdle = 1;
- gestaltPMgrSCC = 2;
- gestaltPMgrSound = 3;
-
- gestaltPPCToolboxAttr
-
- Returns information about the capabilities of the PPC Toolbox.
-
- CONST
- gestaltPPCToolboxPresent = 0;
- gestaltPPCRealTime = 1;
-
- gestaltProcessorType
-
- Returns a value that indicates the type of processor that is currently running.
-
- CONST
- gestalt68000 = 1;
- gestalt68010 = 2;
- gestalt68020 = 3;
- gestalt68030 = 4;
-
- gestaltParityAttr
-
- Returns information about the parity-checking abilities of the machine.
-
- CONST
- gestaltHasParityCapability = 0;
- gestaltParityEnabled = 1;
-
- Note that parity is not considered to be enabled unless all installed memory is
- parity RAM.
-
- gestaltQuickdrawVersion
-
- Returns a 2-byte value indicating the version of QuickDraw currently present.
- The high-order byte of that number represents the major revision number, and the
- low-order byte represents the minor revision number. For example, the Macintosh
- IIci contains QuickDraw version 2.01 in ROM; on that machine, Gestalt returns
- the value $0201.
-
- CONST
- gestaltOriginalQD = $000;
- gestalt8BitQD = $100;
- gestalt32BitQD = $200;
-
- Values having a major revision number of 1 and 2 indicate that Color QuickDraw
- is available, in either the 8-bit or 32-bit version. These results do not,
- however, indicate whether a color monitor is attached to the system. You need to
- use high-level QuickDraw routines to obtain that information.
-
- gestaltPhysicalRAMSize
-
- Returns the number of bytes of physical RAM currently installed.
-
- gestaltResourceMgrAttr
-
- Returns information about the capabilities of the Resource Manager.
-
- CONST
- gestaltPartialRsrcsExist = 0;
- gestaltDecompression = 1;
-
- gestaltScriptMgrVersion
-
- Returns the version number of the Script Manager.
-
- gestaltScriptCount
-
- Returns the number of scripts currently active.
-
- gestaltSoundAttr
-
- Returns information about the sound capabilities of the machine.
-
- CONST
- gestaltStereoCapability = 0;
- gestaltStereoMixing = 1;
-
- The response gestaltStereoCapability indicates that the Sound Manager can play
- stereo sounds. The response gestaltStereoMixing indicates that the sound
- hardware of the machine mixes both left and right channels of stereo sound into
- a single audio signal for the internal speaker.
-
- gestaltTextEditVersion
-
- Returns a value that indicates which version of TextEdit is present.
-
- CONST
- gestaltTE1 = 1;
- gestaltTE2 = 2;
- gestaltTE3 = 3;
- gestaltTE4 = 4;
-
- See the TextEdit chapter in this volume for further information on the
- capabilities of these enhanced versions of TextEdit.
-
- gestaltTimeMgrVersion
-
- Returns a value that indicates the version of the Time Manager that is present.
-
- CONST
- gestaltStandardTimeMgr = 1;
- gestaltRevisedTimeMgr = 2;
- gestaltExtendedTimeMgr = 3;
-
- See the Time Manager chapter in this volume for a complete explanation of the
- capabilities of each of these three versions.
-
- gestaltVMAttr
-
- Returns information about virtual memory.
-
- CONST
- gestaltVMPresent = 1;
- _______________________________________________________________________________
-
- æKY Interpreting…Responses…to…Informational…Selectors
- æC »Interpreting Responses to Informational Selectors Compatibility Guidelines
- _______________________________________________________________________________
-
- Gestalt returns the following responses when passed a predefined informational
- selector.
-
- † Warning: Never infer the existence of certain hardware or software features
- from the responses that Gestalt returns to your application when you pass it
- these selectors.Ê
-
- gestaltMachineType
-
- Returns one of the following values, indicating the type of machine on which the
- application is currently running.
-
- CONST
- gestaltClassic = 1; {Macintosh 128K}
- gestaltMacXL = 2; {Macintosh XL}
- gestaltMac512KE = 3; {Macintosh 512KE }
- gestaltMacPlus = 4; {Macintosh Plus}
- gestaltMacSE = 5; {Macintosh SE}
- gestaltMacII = 6; {Macintosh II}
- gestaltMacIIx = 7; {Macintosh IIx}
- gestaltMacIIcx = 8; {Macintosh IIcx}
- gestaltMacSE030 = 9; {Macintosh SE/30}
- gestaltPortable = 10; {Macintosh Portable}
- gestaltMacIIci = 11; {Macintosh IIci}
-
- Note that the machine type does not indicate which version or size of ROM is
- installed. To determine that information, you should use the two selectors
- gestaltROMSize and gestaltROMVersion.
-
- gestaltROMSize
-
- Returns the size of the installed ROM. The value is returned in a word.
-
- gestaltROMVersion
-
- Returns the version number of the installed ROM.
-
- gestaltSystemVersion
-
- Returns the version number of the currently active System file. This number is
- represented as two byte-long numbers. For example, if your application is
- running in version 6.0.4, then Gestalt returns the value $0604. You should
- ignore the high-order word of the returned value.
-
- _______________________________________________________________________________
-
- æKY Adding…Gestalt…Selectors
- æC »Adding Gestalt Selectors Compatibility Guidelines
- _______________________________________________________________________________
-
- You can add a new selector code to those already understood by Gestalt by
- calling the NewGestalt function. The NewGestalt function requires two
- parameters. The first parameter is the new selector to be registered. The second
- parameter is the address of a selector function, a function that is to be
- executed by Gestalt when it needs to determine what value to pass back when it
- is called with the new selector code.
-
- The selector code is a four-character sequence of type OSType. For example,
- Carl’s Object-Oriented Linker might register itself using the selector code
- 'COOL'. If you have registered a creator string with Apple, you are strongly
- encouraged to use that sequence as your selector code.
-
- Note: Apple reserves for its own use all four-character sequences consisting
- solely of lowercase letters and nonalphabetic ASCII characters.
-
- The selector function whose address you specify when registering a new Gestalt
- selector code can be any function that resides in the system heap and whose
- calling syntax conforms to that defined in “Specifying Gestalt Selector
- Functions” later in this chapter. Listing 3-6 illustrates how to install a
- simple function into the system heap and pass its address to NewGestalt.
-
- Listing 3-6. Installing a selector function into the system heap
-
- PROGRAM NewGestaltSample;
- USES
- Memtypes, OSIntf, ToolIntf, {standard includes}
- PasLibIntf, {for standard I/O, etc.}
- GestaltEqu, {for Gestalt}
- Traps; {for trap numbers}
- CONST
- mySelector = 'COOL'; {Gestalt function selector}
- gstFuncRsrcType = 'GDEF'; {Gestalt function resource type}
- gstFuncRsrcID = 128; {Gestalt function resource ID}
- VAR
- gestaltErr: OSErr; {error returned by Gestalt}
- gstFuncHandle: Handle; {handle to Gestalt function}
- oldGestaltFunc: ProcPtr; {pointer to old function}
- BEGIN
- {first make sure that Gestalt is available}
- IF NOT TrapAvailable(_Gestalt) THEN
- BEGIN
- WriteLn('Gestalt is not implemented.');
- IEexit(1)
- END;
- {load Gestalt function resource into system heap}
- gstFuncHandle := GetResource(gstFuncRsrcType, gstFuncRsrcID);
- IF gstFuncHandle = NIL THEN
- BEGIN
- WriteLn('Could not load Gestalt function resource.');
- IEexit(1)
- END;
- {detach it from the resource map so it stays around}
- DetachResource(gstFuncHandle);
- {add the new selector; first assume that it doesn't already exist}
- gestaltErr := NewGestalt(mySelector, ProcPtr(gstFuncHandle^));
- IF gestaltErr <> noErr THEN
- BEGIN
- WriteLn('Could not add as a new selector.');
- {try to replace existing selector}
- gestaltErr := ReplaceGestalt(mySelector,
- ProcPtr(gstFuncHandle^), oldGestaltFunc);
- IF gestaltErr <> noErr THEN
- BEGIN
- WriteLn('Could not replace selector either.');
- IEexit(1);
- END
- END;
- WriteLn('Selector installed.');
- END.
-
- You can ensure that the new Gestalt selector function is installed into the
- system heap by defining it as a resource (in this case, of type 'GDEF') whose
- resource attributes are resSysHeap and resLocked (in other words, lock the
- resource into the system heap). Listing 3-7 shows the relevant lines from a
- Makefile.
-
- Listing 3-7. Makefile directives to create a 'GDEF' resource
-
- GestaltFunc.p.o ƒ GestaltFunc.p
- Pascal GestaltFunc.p
-
- NewGestaltSample ƒƒ GestaltFunc.p.o
- Link GestaltFunc.p.o -rn ∂
- -ra =resSysHeap,resLocked ∂
- -rt GDEF=128
- -o NewGestaltSample
-
- Listing 3-8 shows the actual function definition, contained in the file
- GestaltFunc.p.
-
- Listing 3-8. Defining a new Gestalt function
-
- UNIT GestaltFunc;
- INTERFACE
- USES
- GestaltEqu; {for Gestalt}
- CONST
- myResult = $87654321; {Gestalt function response}
- FUNCTION gestaltCool (gestaltSelector: OSType;
- VAR gestaltResponse: LongInt) : OSErr;
-
- IMPLEMENTATION
- FUNCTION gestaltCool;
- BEGIN
- gestaltResponse := myResult; {return our response}
- gestaltCool := noErr; {return no error}
- END;
- END.
-
- Because the new selector function resides in the system heap, Gestalt recognizes
- and responds to the new selector until the machines restarts, even if your
- application terminates before that time. As a result, you might want your
- selector function to determine whether your application is still running before
- returning a value to Gestalt. If your application has terminated, the selector
- function should return an error.
-
- Note that if you try to register a selector that has already been registered
- with Gestalt, an error results.
-
- _______________________________________________________________________________
-
- æKY Modifying…Gestalt…Selectors
- æC »Modifying Gestalt Selectors Compatibility Guidelines
- _______________________________________________________________________________
-
- You can use the ReplaceGestalt function to modify the function that Gestalt
- executes when passed a particular selector code. As with the function whose
- address is passed to NewGestalt, the new function must must reside in the system
- heap and have a calling syntax that conforms to that defined in “Specifying
- Gestalt Selector Functions” later in this chapter. Listing 3-6 illustrates how
- to replace a Gestalt selector function.
-
- To allow the new function to call the function previously associated with the
- selector in question, the ReplaceGestalt function returns the address of the
- previous function.
-
- If you attempt to redefine a selector that is not yet defined, an error is
- returned; in that case, the address of the previous function is undefined.
- Accordingly, you should always test the result code of ReplaceGestalt before
- calling Gestalt with the selector in question.
-
- Note: If you modify the function associated with a predefined Gestalt selector,
- do not use any bits in the response parameter that are not documented in this
- chapter. Apple reserves all undocumented bits in the response parameter returned
- by predefined Gestalt selectors.
- _______________________________________________________________________________
-
- æKY Specifying…Gestalt…Selector…Functions
- æC »Specifying Gestalt Selector Functions Compatibility Guidelines
- _______________________________________________________________________________
-
- When you call the NewGestalt and ReplaceGestalt functions, you need to supply
- the address of a selector function that is called when some application passes
- the specified new or replacement selector to Gestalt. This selector function
- should have the following syntax and must reside in the system heap.
-
- FUNCTION selectorFunction (selector: OSType; VAR response: LongInt) : OSErr;
-
- When you pass the new or replacement selector to Gestalt, Gestalt calls the
- specified selector function to determine the information that Gestalt should
- pass back to the calling software. Your function should place the result in the
- long integer pointed to by the response parameter and should return the result
- code that Gestalt will return. This function should be as simple as possible and
- cannot use global variables in the A5 world unless A5 is set up explicitly and
- then restored upon exit. (See the Memory Management chapter in this volume for
- an explanation of setting up and restoring the A5 world.) Other Gestalt
- functions may be called using Gestalt from within this function.
-
- _______________________________________________________________________________
-
- æKY Gestalt…Manager…Routines
- æC »GESTALT MANAGER ROUTINES Compatibility Guidelines
- _______________________________________________________________________________
-
- This section describes the three functions in the Gestalt Manager—Gestalt,
- NewGestalt, and ReplaceGestalt. They allow you, respectively, to determine what
- hardware and software features are present in the operating environment, to add
- new selectors to those understood by the Gestalt function, and to replace the
- functions associated with known selectors.
-
- _______________________________________________________________________________
-
- æKY Getting…Information…About…the…Operating…Environment
- æC »Getting Information About the Operating Environment Compatibility Guidelines
- _______________________________________________________________________________
-
- Use the Gestalt function to obtain information about the operating environment.
- The information you need is indicated by the selector parameter, which Gestalt
- must already recognize.
-
- FUNCTION Gestalt (selector: OSType; VAR response: LongInt) : OSErr;
-
- Trap macro _Gestalt
- On entry D0: selector code
- On exit A0: response
- D0: result code
-
- Upon successful completion of the function, the response parameter contains the
- information requested. Note that Gestalt returns the results from all function
- selectors in a long integer, occupying 4 bytes. In some cases, not all 4 bytes
- are needed to hold the returned information, in which case Gestalt places the
- information in the low-order bytes of the response parameter.
-
- Result codes
- noErr 0 No error
- gestaltUnknownErr –5550 Could not obtain the response
- gestaltUndefSelectorErr –5551 Undefined selector
- _______________________________________________________________________________
-
- æKY Adding…Selector…Codes
- æC »Adding Selector Codes Compatibility Guidelines
- _______________________________________________________________________________
-
- Use the NewGestalt function to add selector codes to those already recognized by
- Gestalt.
-
- FUNCTION NewGestalt (selector: OSType; selectorFunction: ProcPtr) : OSErr;
-
- Trap macro _NewGestalt
- On entry A0: address of new selector function
- D0: selector code
- On exit D0: result code
-
- NewGestalt takes as parameters the selector to be registered and the function
- that Gestalt calls when it receives this selector. The interface for the
- selectorFunction function is defined in “Specifying Gestalt Selector Functions”
- earlier in this chapter.
-
- Result codes
- noErr 0 No error
- memFullErr –108 Ran out of memory
- gestaltDupSelectorErr –5552 Selector already exists
- gestaltLocationErr –5553 Function not in system heap
- _______________________________________________________________________________
-
- æKY Modifying…Selector…Codes
- æC »Modifying Selector Codes Compatibility Guidelines
- _______________________________________________________________________________
-
- The ReplaceGestalt function allows an application to replace the function that
- is currently associated with a selector.
-
- FUNCTION ReplaceGestalt (selector: OSType; selectorFunction: ProcPtr;
- VAR oldGestaltFunction: ProcPtr) : OSErr;
-
- Trap macro _ReplaceGestalt
- On entry A0: address of new selector function
- D0: selector code
- On exit A0: address of old selector function
- D0: result code
-
- The interface for the selectorFunction function is defined in “Specifying
- Gestalt Selector Functions” earlier in this chapter. The new function must
- reside in the system heap and may want to call the function previously
- associated with the named selector. It may do so by using the address returned
- in the parameter oldGestaltFunction. If ReplaceGestalt returns an error of any
- type, then the value of oldGestaltFunction is undefined.
-
- Result codes
- noErr 0 No error
- gestaltUndefSelectorErr –5551 Undefined selector
- gestaltLocationErr –5553 Function not in system heap
-
- _______________________________________________________________________________
-
- æKY Summary…of…the…Gestalt…Manager
- æC »SUMMARY OF THE GESTALT MANAGER Compatibility Guidelines
- _______________________________________________________________________________
-
- The following cards summarize the constants, data types, and routines for the
- Gestalt Manager.
- _______________________________________________________________________________
-
- æKY Gestalt…Manager…Constants
- æC »Constants Compatibility Guidelines
- _______________________________________________________________________________
-
- CONST {environmental selector codes}
- gestaltVersion = 'vers'; {Gestalt version}
- gestaltAddressingModeAttr = 'addr'; {addressing mode attributes}
- gestaltAliasMgrAttr = 'alis'; {Alias Mgr attributes}
- gestaltAppleTalkVersion = 'atlk'; {AppleTalk version}
- gestaltAUXVersion = 'a/ux'; {A/UX version if present}
- gestaltCTBVersion = 'ctbv'; {Comm Toolbox version}
- gestaltDBAccessMgrAttr = 'dbac'; {Database Access Mgr attrs}
- gestaltEditionMgrAttr = 'edtn'; {Edition Mgr attributes}
- gestaltAppleEventsAttr = 'evnt'; {AppleEvents attributes}
- gestaltFolderMgrAttr = 'fold'; {Folder Mgr attributes}
- gestaltFontMgrAttr = 'font'; {Font Mgr attributes}
- gestaltFPUType = 'fpu '; {FPU type}
- gestaltHardwareAttr = 'hdwr'; {hardware attributes}
- gestaltHelpMgrAttr = 'help'; {Help Mgr attributes}
- gestaltKeyboardType = 'kbd '; {keyboard type}
- gestaltLowMemorySize = 'lmem'; {low-memory area size}
- gestaltLogicalRAMSize = 'lram'; {logical RAM size}
- gestaltMiscAttr = 'misc'; {miscellaneous attributes}
- gestaltMMUType = 'mmu '; {MMU type}
- gestaltNotificationMgrAttr = 'nmgr'; {Notification Mgr attrs}
- gestaltOSAttr = 'os '; {O/S attributes}
- gestaltLogicalPageSize = 'pgsz'; {logical page size}
- gestaltPPCToolboxAttr = 'ppc '; {PPC Toolbox attributes}
- gestaltPowerMgrAttr = 'powr'; {Power Mgr attributes}
- gestaltProcessorType = 'proc'; {processor type}
- gestaltParityAttr = 'prty'; {parity attributes}
- gestaltQuickdrawVersion = 'qd '; {QuickDraw version}
- gestaltPhysicalRAMSize = 'ram '; {physical RAM size}
- gestaltResourceMgrAttr = 'rsrc'; {Resource Mgr attributes}
- gestaltScriptMgrVersion = 'scri'; {Script Mgr version}
- gestaltScriptCount = 'scr#'; {# of active script systems}
- gestaltSoundAttr = 'snd '; {sound attributes}
- gestaltTextEditVersion = 'te '; {TextEdit version}
- gestaltTimeMgrVersion = 'tmgr'; {Time Mgr version}
- gestaltVMAttr = 'vm '; {virtual memory attributes}
-
- {informational selector codes}
- gestaltMachineType = 'mach'; {machine type}
- gestaltROMSize = 'rom '; {ROM size}
- gestaltROMVersion = 'romv'; {ROM version}
- gestaltSystemVersion = 'sysv'; {System file version}
-
- {gestaltAddressingModeAttr response values}
- gestalt32BitAddressing = 0; {true if booted in 32-bit mode}
- gestalt32BitSysZone = 1; {32-bit compatible system zone}
- gestalt32BitCapable = 2; {machine is 32-bit capable}
-
- {gestaltAliasMgrAttr response values}
- gestaltAliasMgrPresent = 0; {true if Alias Mgr is present}
-
- {gestaltDBAccessMgrAttr response values}
- gestaltDBAccessMgrPresent = 0; {true if DB Access Mgr present}
-
- {gestaltEditionMgrAttr response values}
- gestaltEditionMgrPresent = 0; {true if Edition Mgr present}
-
- {gestaltAppleEventsAttr response values}
- gestaltAppleEventsPresent = 0; {true if AppleEvents present}
-
- {gestaltFolderMgrAttr response values}
- gestaltFolderMgrPresent = 0; {true if Folder Mgr present}
-
- {gestaltFontMgrAttr response values}
- gestaltOutlineFonts = 0; {true if outline fonts present}
-
- {gestaltFPUType response values}
- gestaltNoFPU = 0; {no FPU present}
- gestalt68881 = 1; {Motorola 68881 present}
- gestalt68882 = 2; {Motorola 68882 present}
-
- {gestaltHardwareAttr response values}
- gestaltHasVIA1 = 0; {has a VIA1}
- gestaltHasVIA2 = 1; {has a VIA2}
- gestaltHasASC = 3; {has an ASC}
- gestaltHasSCC = 4; {has an SCC}
- gestaltHasSCSI = 7; {has SCSI}
-
- {gestaltHelpMgrAttr response values}
- gestaltHelpMgrPresent = 0; {true if Help Mgr present}
-
- {gestaltKeyboardType response values}
- gestaltMacKbd = 1; {Mac keyboard}
- gestaltMacAndPad = 2; {Mac keyboard and keypad}
- gestaltMacPlusKbd = 3; {Mac Plus keyboard}
- gestaltExtADBKbd = 4; {Extended ADB keyboard}
- gestaltStdADBKbd = 5; {Standard ADB keyboard}
- gestaltPrtblADBKbd = 6; {Portable Std ADB keyboard}
- gestaltPrtblISOKbd = 7; {Portable ISO ADB keyboard}
- gestaltStdISOADBKbd = 8; {ISO Std ADB keyboard}
- gestaltExtISOADBKbd = 9; {ISO Ext ADB keyboard}
-
- {gestaltMiscAttr response values}
- gestaltScrollingThrottle = 0; {true if scrolling throttle on}
-
- {gestaltMMUType response values}
- gestaltNoMMU = 0; {no MMU present}
- gestaltAMU = 1; {Mac II addr management unit}
- gestalt68851 = 2; {Motorola 68851 PMMU}
- gestalt68030MMU = 3; {Motorola 68030 built-in MMU}
-
- {gestaltNotificationMgrAttr response values}
- gestaltNotificationMgrPresent = 0; {Notification Mgr present}
-
- {gestaltOSAttr response values}
- gestaltSysZoneGrowable = 0; {system heap can grow}
- gestaltLaunchCanReturn = 1; {can return from launch}
- gestaltLaunchFullFileSpec = 2; {can launch from full filespec}
- gestaltLaunchControl = 3; {launch control support}
- gestaltTempMemSupport = 4; {temp memory support present}
- gestaltRealTempMemory = 5; {temp memory handles are real}
- gestaltTempMemTracked = 6; {temp memory handles tracked}
- gestaltIPCSupport = 7; {IPC support is present}
- gestaltSysDebuggerSupport = 8; {system debugger support}
-
- gestaltPowerMgrAttr response values}
- gestaltPMgrExists = 0; {Power Manager is present}
- gestaltPMgrCPUIdle = 1; {CPU can idle}
- gestaltPMgrSCC = 2; {can stop SCC clock}
- gestaltPMgrSound = 3; {can turn off sound power}
-
- {gestaltPPCToolboxAttr response values}
- gestaltPPCToolboxPresent = 0; {PPC Toolbox is present}
- gestaltPPCRealTime = 1; {real-time delivery}
-
- {gestaltProcessorType response values}
- gestalt68000 = 1;
- gestalt68010 = 2;
- gestalt68020 = 3;
- gestalt68030 = 4;
-
- {gestaltParityAttr response values}
- gestaltHasParityCapability = 0; {machine can check parity}
- gestaltParityEnabled = 1; {parity RAM is installed}
-
- {gestaltQuickdrawVersion response values}
- gestaltOriginalQD = $000; {original QuickDraw}
- gestalt8BitQD = $100; {8-bit Color QuickDraw}
- gestalt32BitQD = $200; {32-Bit Color QuickDraw}
-
- {gestaltResourceMgrAttr response values}
- gestaltPartialRsrcsExist = 0; {partial resource functions exist}
- gestaltDecompression = 1; {}
-
- {gestaltSoundAttr response values}
- gestaltStereoCapability = 0; {stereo capability present}
- gestaltStereoMixing = 1; {stereo mixing on internal speaker}
-
- {gestaltTextEditVersion response values}
- gestaltTE1 = 1; {in MacIIci ROM}
- gestaltTE2 = 2; {with 6.0.4 scripts on Mac IIci}
- gestaltTE3 = 3; {with 6.0.4 scripts on other machines}
- gestaltTE4 = 4; {in 6.0.5 and 7.0}
-
- {gestaltTimeMgrVersion response values}
- gestaltStandardTimeMgr = 1; {standard Time Manager}
- gestaltRevisedTimeMgr = 2; {revised Time Manager}
- gestaltExtendedTimeMgr = 3; {extended Time Manager}
-
- {gestaltVMAttr response values}
- gestaltVMPresent = 1; {virtual memory present}
-
- gestaltMachineType response values}
- gestaltClassic = 1; {Macintosh 128K}
- gestaltMacXL = 2; {Macintosh XL}
- gestaltMac512KE = 3; {Macintosh 512K Enhanced}
- gestaltMacPlus = 4; {Macintosh Plus}
- gestaltMacSE = 5; {Macintosh SE}
- gestaltMacII = 6; {Macintosh II}
- gestaltMacIIx = 7; {Macintosh IIx}
- gestaltMacIIcx = 8; {Macintosh IIcx}
- gestaltMacSE030 = 9; {Macintosh SE/30}
- gestaltPortable = 10; {Macintosh Portable}
- gestaltMacIIci = 11; {Macintosh IIci}
- _______________________________________________________________________________
-
- æKY Gestalt…Manager…Routines…Summary
- æC »Routines Compatibility Guidelines
- _______________________________________________________________________________
-
- FUNCTION Gestalt (selector: OSType; VAR response: LongInt) : OSErr;
-
- FUNCTION NewGestalt (selector: OSType; selectorFunction: ProcPtr) : OSErr;
-
- FUNCTION ReplaceGestalt (selector: OSType; selectorFunction: ProcPtr; VAR
- oldGestaltFunction: ProcPtr) : OSErr;
- _______________________________________________________________________________
-
- æKY Gestalt…Manager…Result…Codes
- æC »Result Codes Compatibility Guidelines
- _______________________________________________________________________________
-
- noErr 0 No error
- memFullErr –108 Ran out of memory
- gestaltUnknownErr –5550 Could not obtain the response
- gestaltUndefSelectorErr –5551 Undefined selector
- gestaltDupSelectorErr –5552 Selector already exists
- gestaltLocationErr –5553 Function not in system heap
- _______________________________________________________________________________
-
-
- æKY ControlManager
- æC
- THE CONTROL MANAGER
- _______________________________________________________________________________
-
- About…The…ControlManager…Chapter
- About…the…Control…Manager
- Controls…and…Windows
- Controls…and…Resources
- Part…Codes
- Control…Records
- Auxiliary…Control…Records
- Control…Color…Tables
- The…Control…Color…Table…Resource
- Using…the…Control…Manager
- Using…Color…Controls
- Control…Manager…Routines
- Defining…Your…Own…Controls
- Formats…of…Resources…for…Controls
- Summary…of…the…Control…Manager
- _______________________________________________________________________________
-
-
-
- æKY About…The…ControlManager…Chapter
- æC »ABOUT THIS CHAPTER ControlManager
- _______________________________________________________________________________
-
- This chapter describes the Control Manager, the part of the Toolbox that deals with
- controls, such as buttons, check boxes, and scroll bars. Using the Control Manager,
- your application can create, manipulate, and dispose of controls.
-
- You should already be familiar with:
-
- • resources, as discussed in the Resource Manager chapter
- • the basic concepts and structures behind QuickDraw, particularly points,
- rectangles, regions, and grafPorts
- • the Toolbox Event Manager
- • the Window Manager
-
- This chapter also describes the enhancements to the Control Manager provided for the
- Macintosh Plus, Macintosh SE, and Macintosh II. A new set of Control Manager routines
- now supports the use of color controls. All handling of color controls is transparent
- to applications that aren’t using the new features.
-
- The structure and size of a control record are unchanged. A new data structure, the
- auxiliary control record, has been introduced to carry additional color information
- for a control, and a new system resource, 'cctb', stores control color table information.
- Three new routines have been added to support the use of color.
-
- _______________________________________________________________________________
-
-
- æKY About…the…Control…Manager
- æC »ABOUT THE CONTROL MANAGER ControlManager
- _______________________________________________________________________________
-
- The Control Manager is the part of the Toolbox that deals with controls. A control is
- an object on the Macintosh screen with which the user, using the mouse, can cause
- instant action with visible results or change settings to modify a future action.
- Using the Control Manager, your application can:
-
- • create and dispose of controls
- • display or hide controls
- • monitor the user’s operation of a control with the mouse and
- respond accordingly
- • read or change the setting or other properties of a control
- • change the size, location, or appearance of a control
-
- Your application performs these actions by calling the appropriate Control Manager
- routines. The Control Manager carries out the actual operations, but
- it’s up to you to decide when, where, and how.
-
- Controls may be of various types (see Figure 1), each with its own characteristic
- appearance on the screen and responses to the mouse. Each individual control has its
- own specific properties— such as its location, size, and setting—but controls of the
- same type behave in the same general way.
-
- Certain standard types of controls are predefined for you. Your application can
- easily create and use controls of these standard types, and can also define its own
- “custom” control types. Among the standard control types are the following:
-
- • Buttons cause an immediate or continuous action when clicked or pressed
- with the mouse. They appear on the screen as rounded-corner rectangles
- with a title centered inside.
-
- • Check boxes retain and display a setting, either checked (on) or
- unchecked (off); clicking with the mouse reverses the setting. On the
- screen, a check box appears as a small square with a title alongside it;
- the box is either filled in with an “X” (checked) or empty (unchecked).
- Check boxes are frequently used to control or modify some future action,
- instead of causing an immediate action of their own.
-
- • Radio buttons also retain and display an on-or-off setting. They’re
- organized into groups, with the property that only one button in the
- group can be on at a time: Clicking one button in a group both turns it
- on and turns off the button that was on, like the buttons on a car radio.
- Radio buttons are used to offer a choice among several alternatives. On
- the screen, they look like round check boxes; the radio button that’s on
- is filled in with a small black circle instead of an “X”.
-
- •••Refer to Figure 1.•••
-
- Figure 1–Controls
-
- Note: The Control Manager doesn’t know how radio buttons are grouped,
- and doesn’t automatically turn one off when the user clicks another
- one on: It’s up to your program to handle this
-
- Another important category of controls is dials. These display the value, magnitude,
- or position of something, typically in some pseudo-analog form such as the position
- of a sliding switch, the reading on a thermometer scale, or the angle of a needle on
- a gauge; the setting may be displayed digitally as well. The control’s moving part
- that displays the current setting is called the indicator. The user may be able to
- change a dial’s setting by dragging its indicator with the mouse, or the dial may
- simply display a value not under the user’s direct control (such as the amount of
- free space remaining on a disk).
-
- One type of dial is predefined for you: The standard Macintosh scroll bars. Figure 2
- shows the five parts of a scroll bar and the terms used by the Control Manager (and
- this chapter) to refer to them. Notice that the part of the scroll bar that Macintosh
- users know as the “scroll box” is called the “thumb” here. Also, for simplicity, the
- terms “up” and “down” are used even when referring to horizontal scroll bars (in
- which case “up” really means “left” and “down” means “right”).
-
- •••Refer to Figure 2.•••
-
- Figure 2–Parts of a Scroll Bar
-
- The up and down arrows scroll the window’s contents a line at a time. The two paging
- regions scroll a “page” (windowful) at a time. The thumb can be dragged to any position
- in the scroll bar, to scroll to a corresponding position within the document. Although
- they may seem to behave like individual controls, these are all parts of a single
- control, the scroll bar type of dial. You can define other dials of any shape or
- complexity for yourself if your application needs them.
-
- A control may be active or inactive. Active controls respond to the user’s mouse
- actions; inactive controls don’t. When an active control is clicked or pressed, it’s
- usually highlighted (see Figure 3). Standard button controls are inverted, but some
- control types may use other forms of highlighting, such as making the outline heavier.
- It’s also possible for just a part of a control to be highlighted: For example, when
- the user presses the mouse button inside a scroll arrow or the thumb in a scroll bar,
- the arrow or thumb (not the whole scroll bar) becomes highlighted until the button is
- released.
-
- •••Refer to Figure 3.•••
-
- Figure 3–Highlighted Active Controls
-
- A control is made inactive when it has no meaning or effect in the current context,
- such as an “Open” button when no document has been selected to open, or a scroll bar
- when there’s currently nothing to scroll to. An inactive control remains visible, but
- is highlighted in some special way, depending on its control type (see Figure 4). For
- example, the title of an inactive button, check box, or radio button is dimmed (drawn
- in gray rather than black).
-
- •••Refer to Figure 4.•••
-
- Figure 4–Inactive Controls
-
- _______________________________________________________________________________
-
-
- æKY Controls…and…Windows
- æC »CONTROLS AND WINDOWS ControlManager
- _______________________________________________________________________________
-
- Every control “belongs” to a particular window: When displayed, the control appears
- within that window’s content region; when manipulated with the mouse, it acts on that
- window. All coordinates pertaining to the control (such as those describing its
- location) are given in its window’s local coordinate system.
-
- Warning: In order for the Control Manager to draw a control properly, the
- control’s window must have the top left corner of its grafPort’s
- portRect at coordinates (0,0). If you change a window’s local
- coordinate system for any reason (with the QuickDraw procedure
- SetOrigin), be sure to change it back—so that the top left corner
- is again at (0,0)—before drawing any of its controls. Since almost
- all of the Control Manager routines can (at least potentially)
- redraw a control, the safest policy is simply to change the
- coordinate system back before calling any Control Manager routine.
-
- Normally you’ll include buttons and check boxes in dialog or alert windows only. You
- create such windows with the Dialog Manager, and the Dialog Manager takes care of
- drawing the controls and letting you know whether the user clicked one of them. See
- the Dialog Manager chapter for details.
-
- _______________________________________________________________________________
-
-
- æKY Controls…and…Resources
- æC »CONTROLS AND RESOURCES ControlManager
- _______________________________________________________________________________
-
- The relationship between controls and resources is analogous to the relationship
- between windows and resources: Just as there are window definition functions and
- window templates, there are control definition functions and control templates.
-
- Each type of control has a control definition function that determines how controls
- of that type look and behave. The Control Manager calls the control definition function
- whenever it needs to perform a type-dependent action, such as drawing the control on
- the screen. Control definition functions are stored as resources and accessed through
- the Resource Manager. The system resource file includes definition functions for the
- standard control types (buttons, check boxes, radio buttons, and scroll bars). If you
- want to define your own, nonstandard control types, you’ll have to write control
- definition functions for them, as described later in the section “Defining Your Own
- Controls”.
-
- When you create a control, you specify its type with a control definition ID, which
- tells the Control Manager the resource ID of the definition function for that control
- type. The Control Manager provides the following predefined constants for the definition
- IDs of the standard control types:
-
- CONST pushButProc = 0; {simple button}
- checkBoxProc = 1; {check box}
- radioButProc = 2; {radio button}
- scrollBarProc = 16; {scroll bar}
-
- Note: The control definition function for scroll bars figures out whether
- a scroll bar is vertical or horizontal from a rectangle you specify
- when you create the control.
-
- The title of a button, check box, or radio button normally appears in the system
- font, but you can add the following constant to the definition ID to specify that you
- instead want to use the font currently associated with the window’s grafPort:
-
- CONST useWFont = 8; {use window's font}
-
- To create a control, the Control Manager needs to know not only the control definition
- ID but also other information specific to this control, such as its title (if any),
- the window it belongs to, and its location within the window. You can supply all the
- needed information in individual parameters to a Control Manager routine, or you can
- store it in a control template in a resource file and just pass the template’s resource
- ID. Using templates is highly recommended, since it simplifies the process of creating
- controls and isolates the control descriptions from your application’s code.
-
- _______________________________________________________________________________
-
-
- æKY Part…Codes
- æC »PART CODES ControlManager
- _______________________________________________________________________________
-
- Some controls, such as buttons, are simple and straightforward. Others can be complex
- objects with many parts: For example, a scroll bar has two scroll arrows, two paging
- regions, and a thumb (see Figure 2 above). To allow different parts of a control to
- respond to the mouse in different ways, many of the Control Manager routines accept a
- part code as a parameter or return one as a result.
-
- A part code is an integer between 1 and 253 that stands for a particular part of a
- control. Each type of control has its own set of part codes, assigned by the control
- definition function for that type. A simple control such as a button or check box
- might have just one “part” that encompasses the entire control; a more complex control
- such as a scroll bar can have as many parts as are needed to define how the control
- operates.
-
- Note: The values 254 and 255 aren’t used for part codes—254 is reserved
- for future use, and 255 means the entire control is inactive.
-
- The part codes for the standard control types are as follows:
-
- CONST inButton = 10; {simple button}
- inCheckBox = 11; {check box or radio button}
- inUpButton = 20; {up arrow of a scroll bar}
- inDownButton = 21; {down arrow of a scroll bar}
- inPageUp = 22; {"page up" region of a scroll bar}
- inPageDown = 23; {"page down" region of a scroll bar}
- inThumb = 129; {thumb of a scroll bar}
-
- Notice that inCheckBox applies to both check boxes and radio buttons.
-
- Note: For special information about assigning part codes to your own
- control types, see “Defining Your Own Controls”.
-
- _______________________________________________________________________________
-
-
- æKY Control…Records
- æC »CONTROL RECORDS ControlManager
- _______________________________________________________________________________
-
- Every control is represented internally by a control record containing all pertinent
- information about that control. The control record contains the following:
-
- • A pointer to the window the control belongs to.
- • A handle to the next control in the window’s control list.
- • A handle to the control definition function.
- • The control’s title, if any.
- • A rectangle that completely encloses the control, which determines
- the control’s size and location within its window. The entire control,
- including the title of a check box or radio button, is drawn inside
- this rectangle.
- • An indication of whether the control is currently active and how it’s
- to be highlighted.
- • The current setting of the control (if this type of control retains a
- setting) and the minimum and maximum values the setting can assume. For
- check boxes and radio buttons, a setting of 0 means the control is off
- and 1 means it’s on.
-
- The control record also contains an indication of whether the control is currently
- visible or invisible. These terms refer only to whether the control is drawn in its
- window, not to whether you can see it on the screen. A control may be “visible” and
- still not appear on the screen, because it’s obscured by overlapping windows or other
- objects.
-
- There’s a field in the control record for a pointer to the control’s default action
- procedure. An action procedure defines some action to be performed repeatedly for as
- long as the user holds down the mouse button inside the control. The default action
- procedure may be used by the Control Manager function TrackControl if you call it
- without passing a pointer to an action procedure; this is discussed in detail in the
- description of TrackControl in the “Control Manager Routines” section.
-
- Finally, the control record includes a 32-bit reference value field, which is reserved
- for use by your application. You specify an initial reference value when you create a
- control, and can then read or change the reference value whenever you wish.
-
- The data type for a control record is called ControlRecord. A control record is
- referred to by a handle:
-
- TYPE ControlPtr = ^ControlRecord;
- ControlHandle = ^ControlPtr;
-
- The Control Manager functions for creating a control return a handle to a newly
- allocated control record; thereafter, your program should normally refer to the
- control by this handle. Most of the Control Manager routines expect a control handle
- as their first parameter.
-
- You can store into and access most of a control record’s fields with Control Manager
- routines, so normally you don’t have to know the exact field names. However, if you
- want more information about the exact structure of a control record—if you’re defining
- your own control types, for instance—it’s given below.
-
- _______________________________________________________________________________
-
- »The ControlRecord Data Type
-
- The ControlRecord data type is defined as follows:
-
- TYPE ControlRecord =
- PACKED RECORD
- nextControl: ControlHandle; {next control}
- contrlOwner: WindowPtr; {control's window}
- contrlRect: Rect; {enclosing rectangle}
- contrlVis: Byte; {255 if visible}
- contrlHilite: Byte; {highlight state}
- contrlValue: INTEGER; {control's current setting}
- contrlMin: INTEGER; {control's minimum setting}
- contrlMax: INTEGER; {control's maximum setting}
- contrlDefProc: Handle; {control definition function}
- contrlData: Handle; {data used by contrlDefProc}
- contrlAction: ProcPtr; {default action procedure}
- contrlRfCon: LONGINT; {control's reference value}
- contrlTitle: Str255 {control's title}
- END;
-
- NextControl is a handle to the next control associated with this control’s window.
- All the controls belonging to a given window are kept in a linked list, beginning in
- the controlList field of the window record and chained together through the nextControl
- fields of the individual control records. The end of the list is marked by a NIL
- value; as new controls are created, they’re added to the beginning of the list.
-
- ContrlOwner is a pointer to the window that this control belongs to.
-
- ContrlRect is the rectangle that completely encloses the control, in the local coordinates
- of the control’s window.
-
- When contrlVis is 0, the control is currently invisible; when it’s 255, the control
- is visible.
-
- ContrlHilite specifies whether and how the control is to be highlighted, indicating
- whether it’s active or inactive. The HiliteControl procedure lets you set this field;
- see the description of HiliteControl for more information about the meaning of the
- field’s value.
-
- ContrlValue is the control’s current setting. For check boxes and radio buttons, 0
- means the control is off and 1 means it’s on. For dials, the fields contrlMin and
- contrlMax define the range of possible settings; contrlValue may take on any value
- within that range. Other (custom) control types can use these three fields as they
- see fit.
-
- ContrlDefProc is a handle to the control definition function for this type of control.
- When you create a control, you identify its type with a control definition ID, which
- is converted into a handle to the control definition function and stored in the
- contrlDefProc field. Thereafter, the Control Manager uses this handle to access the
- definition function; you should never need to refer to this field directly.
-
- Note: When not running in 32-bit mode, the high-order byte of the
- contrlDefProc field contains some additional information that
- the Control Manager gets from the control definition ID; for
- details, see the section “Defining Your Own Controls”.
-
- ContrlData is reserved for use by the control definition function, typically to hold
- additional information specific to a particular control type. For example, the standard
- definition function for scroll bars uses this field for a handle to the region containing
- the scroll bar’s thumb. If no more than four bytes of additional information are
- needed, the definition function can store the information directly in the contrlData
- field rather than use a handle.
-
- ContrlAction is a pointer to the control’s default action procedure, if any. The
- Control Manager function TrackControl may call this procedure to respond to the
- user’s dragging the mouse inside the control.
-
- ContrlRfCon is the control’s reference value field, which the application may store
- into and access for any purpose.
-
- ContrlTitle is the control’s title, if any.
-
- _______________________________________________________________________________
-
-
- æKY Auxiliary…Control…Records
- æC »AUXILIARY CONTROL RECORDS ControlManager
- _______________________________________________________________________________
-
- The information needed for drawing controls in color is kept in a linked list of
- auxiliary control records, beginning in the global variable AuxCtlHead.
- (Notice that there is just one global list for all controls in all windows, not a
- separate one for each window.) Each window record has a handle to the list of controls.
- Figure 5 shows the auxiliary control list structure.
-
- •••Refer to Figure 5.•••
-
- Figure 5–Auxiliary Control List
-
- Each auxiliary control record is a relocatable object residing in the application
- heap. The most important information it holds is a handle to the control’s individual
- color table (see the “Control Color Tables” section). The rest of the record consists
- of a link to the next record in the list, a field that identifies the control’s
- owner, a 4-byte field reserved for future expansion, and a 4-byte reference constant
- for use by the application:
-
- TYPE
- AuxCtlHandle = ^AuxCtlPtr;
- AuxCtlPtr = ^AuxCtlRec;
- AuxCtlRec = RECORD
- acNext: AuxCtlHandle; {handle to next record in list}
- acOwner: ControlHandle; {handle to owning control}
- acCTable: CCTabHandle; {handle to control's color }
- { table}
- acFlags: INTEGER; {miscellaneous flags; reserved}
- acReserved: LONGINT; {reserved for future expansion}
- acRefCon: LONGINT {reserved for application use}
- END;
-
- Field descriptions
-
- acNext The acNext field contains a handle to the next record in
- the auxiliary control list.
-
- acOwner The acOwner field contains the handle of the control to
- which this auxiliary record belongs. Used as an ID field.
-
- acCTable The acCTable contains the handle to the control’s color
- table (see “Control Color Tables” below).
-
- acFlags The acFlags field contains miscellaneous flags for use by
- the Control Manager; this field is reserved.
-
- acReserved The acReserved field is reserved for future expansion;
- this must be set to 0 for future compatibility.
-
- acRefCon The acRefCon field is a reference constant for use by
- the application.
-
- Not every control needs an auxiliary control record. When an application is started,
- a resource containing a default color table is loaded from the system resource file;
- this resource defines a standard set of control colors. Since there is no InitControls
- routine, this happens when an application calls InitWindows.
-
- Separate auxiliary control records are needed only for controls whose color usage
- differs from the default. Each such nonstandard control must have its own auxiliary
- record, even if it uses the same colors as another control. This allows two or more
- auxiliary records to share the same control color table. If the control color table
- is a resource, it won’t be deleted by DisposeControl. When using an auxiliary record
- that is not stored as a resource, the application should not deallocate the color
- table if another control is still using it.
-
- A control created from scratch will initially have no auxiliary control record. If
- it is to use nonstandard colors, it must be given an auxiliary record and a color
- table with SetCtlColor (see the “Control Manager Routines” section). Such a control
- should normally be made invisible at creation and then displayed with ShowControl
- after the colors are set. For controls created from a 'CNTL' resource, the color
- table can be specified as a resource as well. See the section titled “The Control
- Color Table Resource”.
-
- A/UX systems: When using 32-bit mode. every control has its own auxiliary
- record. If there is no specific set of control colors for
- this control, the acCTable will point to the default color table.
-
- _______________________________________________________________________________
-
-
- æKY Control…Color…Tables
- æC »CONTROL COLOR TABLES ControlManager
- _______________________________________________________________________________
-
- The contents and meaning of a control’s color table are determined by its control
- definition function (see “The Control Color Table Resource” section). The CTabHandle
- parameter used in the Color Control Manager routines provides a handle to the control
- color table. The components of a control color table are defined as follows:
-
- TYPE
- CCTabHandle = ^CCTabPtr;
- CCTabPtr = ^CtlCTab;
- CtlCTab = RECORD
- ccSeed: LONGINT; {not used for controls}
- ccRider: INTEGER; {not used for controls}
- ctSize: INTEGER; {number of entries in table –1}
- ctTable: cSpecArray {array of ColorSpec records}
- END;
-
- Field descriptions
-
- ccSeed The ccSeed field is unused in control color tables.
-
- ccRider The ccRider field is unused in control color tables.
-
- ctSize The ctSize field defines the number of elements in the table,
- minus one. For controls drawn with the standard definition
- procedure, this field is always 3.
-
- ctTable The ctTable field holds an array of colorSpec records. Each
- colorSpec is made up of a partIdentifier field and a partRGB
- field. The partIdentifier field holds an integer which
- associates an RGBColor to a particular part of the control.
- The definition procedures attempt to find the appropriate part
- identifier when preparing to draw a part. If that part
- identifier is not found, the first color in the table is
- used to draw the part. The part identifiers can appear in any
- order in the table. The partRGB field specifies a standard RGB
- color record, indicating what absolute color will be used to
- draw the control part found in the partIdentifier field.
-
- A standard control color table is shown in Figure 6.
-
- •••Refer to Figure 6.•••
-
- Figure 6–Control Color Table
-
- The 'cctb' resource is an exact image of this control table data structure, and is
- stored in the same format as 'clut' color table resources.
-
- Standard buttons, check boxes, and radio buttons use a four-element color table with
- part identifiers as shown below:
-
- cFrameColor (0) Frame color
- cBodyColor (1) Fill color for body of control
- cTextColor (2) Text color
- cThumbColor (3) Unused
-
- When highlighted, plain buttons exchange their body and text colors (colors 1 and 2);
- check boxes and radio buttons change their appearance without changing colors. All
- three types indicate deactivation by dimming their text with no change in colors.
-
- Standard scroll bars use a four-element color table with part identifiers as shown
- below:
-
- cFrameColor (0) Frame color, foreground color for shaft and arrows
- cBodyColor (1 Background color for shaft and arrows
- cTextColor (2) Unused
- cThumbColor (3) Fill color for thumb
-
- When highlighted, the arrows are filled with the foreground color (color 0) within
- the arrow outline. A deactivated scroll bar shows no indicator, and displays its
- shaft in solid background color (color 1), with no pattern.
-
- The 'cctb' resource = 0 is read into the application heap when the application starts,
- and serves as the default control color table. The last record in the auxiliary
- control list points to the default 'cctb' resource. When drawing a control, the
- standard control definition function searches the list for an auxiliary control
- record whose acOwner points to the control being drawn. If it finds such a record,
- it uses the color table designated by that record; if it doesn’t find one before
- reaching the default record at the end of the list, it uses the default color table
- instead. All types of controls share the same default record. The default auxiliary
- control record is recognized by NIL values in both its acNext and acOwner fields; the
- application must not change these fields.
-
- A nonstandard control definition function can use color tables of any desired size
- and define their contents in any way it wishes, except that part indices 1 to 127 are
- reserved for system definition. Any such nonstandard function should take care to
- bypass the defaulting mechanism just described, by allocating an explicit auxiliary
- record for every control it creates.
-
- _______________________________________________________________________________
-
-
- æKY The…Control…Color…Table…Resource
- æC »THE CONTROL COLOR TABLE RESOURCE ControlManager
- _______________________________________________________________________________
-
- The system default control colors are stored in the System file and ROMResources as
- 'cctb' resource = 0. By including a 'cctb' resource = 0 in your application, it is
- possible to change the default colors that will be used for all controls, unless a
- specific 'cctb' exists for a control defined within the application.
-
- When you use GetNewControl for the control resource 'CNTL', GetNewControl will attempt
- to load a 'cctb' resource with the same ID as the 'CNTL' resource ID, if one is
- present. It then executes the SetCtlColor call.
-
- The following part identifiers for control elements should be present in the ColorSpec.value
- field:
-
- cFrameColor (0) Frame color
- cBodyColor (1) Fill color for body of control
- cTextColor (2) Text color
- cThumbColor (3) Thumb color
-
- These identifiers may be present in any order; for instance, the text or indicator
- color values may be stored before the fill and frame colors in the ColorSpec record
- structure. If a part identifier is not found, then the first color in the color table
- will be used.
-
- _______________________________________________________________________________
-
-
- æKY Using…the…Control…Manager
- æC »USING THE CONTROL MANAGER ControlManager
- _______________________________________________________________________________
-
- To use the Control Manager, you must have previously called InitGraf to initialize
- QuickDraw, InitFonts to initialize the Font Manager, and InitWindows to initialize
- the Window Manager.
-
- Note: For controls in dialogs or alerts, the Dialog Manager makes some
- of the basic Control Manager calls for you; see the Dialog Manager
- chapter for more information.
-
- Where appropriate in your program, use NewControl or GetNewControl to create any
- controls you need. NewControl takes descriptive information about the new control
- from its parameters; GetNewControl gets the information from a control template in a
- resource file. When you no longer need a control, call DisposeControl to remove it
- from its window’s control list and release the memory it occupies. To dispose of all
- of a given window’s controls at once, use KillControls.
-
- Note: The Window Manager procedures DisposeWindow and CloseWindow
- automatically dispose of all the controls associated with the
- given window.
-
- When the Toolbox Event Manager function GetNextEvent reports that an update event has
- occurred for a window, the application should call DrawControls to redraw the window’s
- controls as part of the process of updating the window.
-
- After receiving a mouse-down event from GetNextEvent, do the following:
-
- 1. First call FindWindow to determine which part of which window the
- mouse button was pressed in.
-
- 2. If it was in the content region of the active window, call FindControl
- for that window to find out whether it was in an active control, and
- if so, in which part of which control.
-
- 3. Finally, take whatever action is appropriate when the user presses
- the mouse button in that part of the control, using routines such
- as TrackControl (to perform some action repeatedly for as long as
- the mouse button is down, or to allow the user to drag the control’s
- indicator with the mouse), DragControl (to pull an outline of the
- control across the screen and move the control to a new location),
- and HiliteControl (to change the way the control is highlighted).
-
- For the standard control types, step 3 involves calling TrackControl. TrackControl
- handles the highlighting of the control and determines whether the mouse is still in
- the control when the mouse button is released. It also handles the dragging of the
- thumb in a scroll bar and, via your action procedure, the response to presses or
- clicks in the other parts of a scroll bar. When TrackControl returns the part code
- for a button, check box, or radio button, the application must do whatever is appropriate
- as a response to a click of that control. When TrackControl returns the part code for
- the thumb of a scroll bar, the application must scroll to the corresponding relative
- position in the document.
-
- The application’s exact response to mouse activity in a control that retains a setting
- will depend on the current setting of the control, which is available from the GetCtlValue
- function. For controls whose values can be set by the user, the SetCtlValue procedure
- may be called to change the control’s setting and redraw the control accordingly.
- You’ll call SetCtlValue, for example, when a check box or radio button is clicked, to
- change the setting and draw or clear the mark inside the control.
-
- Wherever needed in your program, you can call HideControl to make a control invisible
- or ShowControl to make it visible. Similarly, MoveControl, which simply changes a
- control’s location without pulling around an outline of it, can be called at any
- time, as can SizeControl, which changes its size. For example, when the user changes
- the size of a document window that contains a scroll bar, you’ll call HideControl to
- remove the old scroll bar, MoveControl and SizeControl to change its location and
- size, and ShowControl to display it as changed.
-
- Whenever necessary, you can read various attributes of a control with GetCTitle,
- GetCtlMin, GetCtlMax, GetCRefCon, or GetCtlAction; you can change them with SetCTitle,
- SetCtlMin, SetCtlMax, SetCRefCon, or SetCtlAction.
-
- _______________________________________________________________________________
-
-
- æKY Using…Color…Controls
- æC »USING COLOR CONTROLS ControlManager
- _______________________________________________________________________________
-
- The following caveats apply to the use of color with controls:
-
- • Controls are drawn in the window port, which by default is an
- old-style GrafPort. This limits color matching to the eight old
- QuickDraw colors. To achieve full RGB display with controls, the
- window must be opened as a cGrafPort, using NewCWindow, GetNewCWindow,
- or any other window routine that creates a color window.
-
- Since there is no “InitControls” call, a default AuxCtlRec is created and intialized
- on the application heap when InitWindows is executed. When a new control is created
- with the NewControl routine, no entry is added to the AuxList, and the control will
- use the default colors. If SetCtlColor is used with a different color set of a control,
- a new AuxList will be allocated and added to the head of the list. The CloseControl
- routine disposes of the AuxCtlRec.
-
- Often a new control is created from a 'CNTL' resource, using GetNewControl. A new
- AuxRec is allocated if the resource file contains a 'cctb' resource type with the
- same resource ID as the 'CNTL' resource. Otherwise, the default colors are used.
-
- The Control Manager supports controls that have color tables with more than four
- elements. To create a control with more than four colors, you must create a custom
- 'CDEF' that can access a larger color table.The interpretation of the partIdentifiers
- is determined by the 'CDEF'. If your application includes a
- 'CDEF' that recognizes more than four partIdentifiers, it should use partIdentifiers
- 0–3 in the same way as the standard control defprocs. An application with a custom
- 'CDEF" should use the _SysEnvirons routine upon entry to the defproc to determine the
- configuration of the system.
-
- _______________________________________________________________________________
-
-
- æKY Control…Manager…Routines
- æC »CONTROL MANAGER ROUTINES ControlManager
- _______________________________________________________________________________
-
- »Initialization and Allocation
-
- FUNCTION NewControl (theWindow: WindowPtr; boundsRect: Rect; title: Str255;
- visible: BOOLEAN; value: INTEGER; min,max: INTEGER;
- procID: INTEGER; refCon: LONGINT) : ControlHandle;
-
- NewControl creates a control, adds it to the beginning of theWindow’s control list,
- and returns a handle to the new control. The values passed as parameters are stored
- in the corresponding fields of the control record, as described below. The field that
- determines highlighting is set to 0 (no highlighting) and the pointer to the default
- action procedure is set to NIL (none).
-
- Note: The control definition function may do additional initialization,
- including changing any of the fields of the control record. The only
- standard control for which additional initialization is done is the
- scroll bar; its control definition function allocates space for a
- region to hold the thumb and stores the region handle in the
- contrlData field of the control record.
-
- TheWindow is the window the new control will belong to. All coordinates pertaining to
- the control will be interpreted in this window’s local coordinate system.
-
- BoundsRect, given in theWindow’s local coordinates, is the rectangle that encloses
- the control and thus determines its size and location. Note the following about the
- enclosing rectangle for the standard controls:
-
- • Simple buttons are drawn to fit the rectangle exactly. (The control
- definition function calls the QuickDraw procedure FrameRoundRect.) To
- allow for the tallest characters in the system font, there should be
- at least a 20-point difference between the top and bottom coordinates
- of the rectangle.
- • For check boxes and radio buttons, there should be at least a 16-point
- difference between the top and bottom coordinates.
- • By convention, scroll bars are 16 pixels wide, so there should be a
- 16-point difference between the left and right (or top and bottom)
- coordinates. (If there isn’t, the scroll bar will be scaled to fit
- the rectangle.) A standard scroll bar should be at least 48 pixels
- long, to allow room for the scroll arrows and thumb.
-
- Title is the control’s title, if any (if none, you can just pass the empty string as
- the title). Be sure the title will fit in the control’s enclosing rectangle; if it
- won’t it will be truncated on the right for check boxes and radio buttons, or centered
- and truncated on both ends for simple buttons.
-
- Note: Some non-Roman systems write text from right-to-left, in which
- case radio buttons and check boxes are drawn with their titles
- on the left of the control. They are also truncated on the left.
- See the Script Manager chapter for more information.
-
- If the visible parameter is TRUE, NewControl draws the control.
-
- Note: It does not use the standard window updating mechanism, but
- instead draws the control immediately in the window.
-
- The min and max parameters define the control’s range of possible settings; the value
- parameter gives the initial setting. For controls that don’t retain a setting, such
- as buttons, the values you supply for these parameters will be stored in the control
- record but will never be used. So it doesn’t matter what values you give for those
- controls—0 for all three parameters will do. For controls that just retain an on-or-off
- setting, such as check boxes or radio buttons, min should be 0 (meaning the control
- is off) and max should be 1
- (meaning it’s on). For dials, you can specify whatever values are appropriate for
- min, max, and value.
-
- ProcID is the control definition ID, which leads to the control definition function
- for this type of control. (The function is read into memory if it
- isn’t already in memory.) The control definition IDs for the standard control types
- are listed above under “Controls and Resources”. Control definition IDs for custom
- control types are discussed later under “Defining Your Own Controls”.
-
- RefCon is the control’s reference value, set and used only by your application.
-
- FUNCTION GetNewControl (controlID: INTEGER;
- theWindow: WindowPtr) : ControlHandle;
-
- GetNewControl creates a control from a control template stored in a resource file,
- adds it to the beginning of theWindow’s control list, and returns a handle to the new
- control. ControlID is the resource ID of the template. GetNewControl works exactly
- the same as NewControl (above), except that it gets the initial values for the new
- control’s fields from the specified control template instead of accepting them as
- parameters. If the control template can’t be read from the resource file, GetNewControl
- returns NIL. It releases the memory occupied by the resource before returning.
-
- PROCEDURE DisposeControl (theControl: ControlHandle);
-
- Assembly-language note: The macro you invoke to call DisposeControl from
- assembly language is named _DisposControl.
-
- DisposeControl removes theControl from the screen, deletes it from its window’s
- control list, and releases the memory occupied by the control record and any data
- structures associated with the control.
-
- PROCEDURE KillControls (theWindow: WindowPtr);
-
- KillControls disposes of all controls associated with theWindow by calling DisposeControl
- (above) for each.
-
- Note: Remember that the Window Manager procedures CloseWindow and
- DisposeWindow automatically dispose of all controls associated
- with the given window.
-
- _______________________________________________________________________________
-
- »Control Display
-
- These procedures affect the appearance of a control but not its size or location.
-
- PROCEDURE SetCTitle (theControl: ControlHandle; title: Str255);
-
- SetCTitle sets theControl’s title to the given string and redraws the control.
-
- PROCEDURE GetCTitle (theControl: ControlHandle; VAR title: Str255);
-
- GetCTitle returns theControl’s title as the value of the title parameter.
-
- PROCEDURE HideControl (theControl: ControlHandle);
-
- HideControl makes theControl invisible. It fills the region the control occupies
- within its window with the background pattern of the window’s grafPort. It also adds
- the control’s enclosing rectangle to the window’s update region, so that anything
- else that was previously obscured by the control will reappear on the screen. If the
- control is already invisible, HideControl has no effect.
-
- PROCEDURE ShowControl (theControl: ControlHandle);
-
- ShowControl makes theControl visible. The control is drawn in its window but may be
- completely or partially obscured by overlapping windows or other objects. If the
- control is already visible, ShowControl has no effect.
-
- PROCEDURE DrawControls (theWindow: WindowPtr);
-
- DrawControls draws all controls currently visible in theWindow. The controls are
- drawn in reverse order of creation; thus in case of overlap the earliest-created
- controls appear frontmost in the window.
-
- Note: Window Manager routines such as SelectWindow, ShowWindow, and
- BringToFront do not automatically call DrawControls to display
- the window’s controls. They just add the appropriate regions to
- the window’s update region, generating an update event. Your program
- should always call DrawControls explicitly upon receiving an update
- event for a window that contains controls.
-
- PROCEDURE Draw1Control (theControl: ControlHandle); [128K ROM]
-
- Draw1Control draws the specified control if it’s visible within the window.
-
- PROCEDURE UpdtControl (theWindow: WindowPtr; updateRgn: RgnHandle); [128K ROM]
-
- UpdtControl is a faster version of the DrawControls procedure. Instead of drawing all
- of the controls in theWindow, UpdtControl draws only the controls that are in the
- specified update region. UpdtControl is called in response to an update event, and is
- usually bracketed by calls to the Window Manager procedures BeginUpdate and EndUpdate.
- UpdateRgn should be set to the visRgn of theWindow’s port (for more details, see the
- BeginUpdate procedure in the Window Manager chapter).
-
- Note: In general, controls are in a dialog box and are automatically
- drawn by the DrawDialog procedure.
-
- PROCEDURE HiliteControl (theControl: ControlHandle; hiliteState: INTEGER);
-
- HiliteControl changes the way theControl is highlighted. HiliteState has one of the
- following values:
-
- • The value 0 means no highlighting. (The control is active.)
- • A value between 1 and 253 is interpreted as a part code designating
- the part of the (active) control to be highlighted.
- • The value 255 means that the control is to be made inactive and
- highlighted accordingly.
-
- Note: The value 254 should not be used; this value is reserved for future use.
-
- HiliteControl calls the control definition function to redraw the control with its
- new highlighting.
-
- _______________________________________________________________________________
-
- »Mouse Location
-
- FUNCTION FindControl (thePoint: Point; theWindow: WindowPtr; VAR whichControl:
- ControlHandle) : INTEGER;
-
- When the Window Manager function FindWindow reports that the mouse button was pressed
- in the content region of a window, and the window contains controls, the application
- should call FindControl with theWindow equal to the window pointer and thePoint equal
- to the point where the mouse button was pressed (in the window’s local coordinates).
- FindControl tells which of the window’s controls, if any, the mouse button was pressed
- in:
-
- • If it was pressed in a visible, active control, FindControl sets the
- whichControl parameter to the control handle and returns a part code
- identifying the part of the control that it was pressed in.
- • If it was pressed in an invisible or inactive control, or not in any
- control, FindControl sets whichControl to NIL and returns 0 as its result.
-
- Warning: Notice that FindControl expects the mouse point in the window’s
- local coordinates, whereas FindWindow expects it in global
- coordinates. Always be sure to convert the point to local
- coordinates with the QuickDraw procedure GlobalToLocal before
- calling FindControl.
-
- Note: FindControl also returns NIL for whichControl and 0 as its result
- if the window is invisible or doesn’t contain the given point. In
- these cases, however, FindWindow wouldn’t have returned this window
- in the first place, so the situation should never arise.
-
- FUNCTION TrackControl (theControl: ControlHandle; startPt: Point;
- actionProc: ProcPtr) : INTEGER;
-
- When the mouse button is pressed in a visible, active control, the application should
- call TrackControl with theControl equal to the control handle and startPt equal to
- the point where the mouse button was pressed (in the local coordinates of the control’s
- window). TrackControl follows the movements of the mouse and responds in whatever way
- is appropriate until the mouse button is released; the exact response depends on the
- type of control and the part of the control in which the mouse button was pressed. If
- highlighting is appropriate, TrackControl does the highlighting, and undoes it before
- returning. When the mouse button is released, TrackControl returns with the part code
- if the mouse is in the same part of the control that it was originally in, or with 0
- if not
- (in which case the application should do nothing).
-
- If the mouse button was pressed in an indicator, TrackControl drags a dotted outline
- of it to follow the mouse. When the mouse button is released, TrackControl calls the
- control definition function to reposition the control’s indicator. The control definition
- function for scroll bars responds by redrawing the thumb, calculating the control’s
- current setting based on the new relative position of the thumb, and storing the
- current setting in the control record; for example, if the minimum and maximum settings
- are 0 and 10, and the thumb is in the middle of the scroll bar, 5 is stored as the
- current setting. The application must then scroll to the corresponding relative
- position in the document.
-
- TrackControl may take additional actions beyond highlighting the control or dragging
- the indicator, depending on the value passed in the actionProc parameter, as described
- below. The following tells you what to pass for the standard control types; for a
- custom control, what you pass will depend on how the control is defined.
-
- • If actionProc is NIL, TrackControl performs no additional actions. This
- is appropriate for simple buttons, check boxes, radio buttons, and the
- thumb of a scroll bar.
- • ActionProc may be a pointer to an action procedure that defines some
- action to be performed repeatedly for as long as the user holds down
- the mouse button. (See below for details.)
- • If actionProc is POINTER(–1), TrackControl looks in the control record
- for a pointer to the control’s default action procedure. If that field
- of the control record contains a procedure pointer, TrackControl uses
- the action procedure it points to; if the field contains POINTER (–1),
- TrackControl calls the control definition function to perform the
- necessary action. (If the field contains NIL, TrackControl does nothing.)
-
- The action procedure in the control definition function is described in the section
- “Defining Your Own Controls”. The following paragraphs describe only the action
- procedure whose pointer is passed in the actionProc parameter or stored in the control
- record.
-
- If the mouse button was pressed in an indicator, the action procedure (if any) should
- have no parameters. This procedure must allow for the fact that the mouse may not be
- inside the original control part.
-
- If the mouse button was pressed in a control part other than an indicator, the action
- procedure should be of the form
-
- PROCEDURE MyAction (theControl: ControlHandle; partCode: INTEGER);
-
- In this case, TrackControl passes the control handle and the part code to the action
- procedure. (It passes 0 in the partCode parameter if the mouse has moved outside the
- original control part.) As an example of this type of action procedure, consider what
- should happen when the mouse button is pressed in a scroll arrow or paging region in
- a scroll bar. For these cases, your action procedure should examine the part code to
- determine exactly where the mouse button was pressed, scroll up or down a line or
- page as appropriate, and call SetCtlValue to change the control’s setting and redraw
- the thumb.
-
- Warning: Since it has a different number of parameters depending on whether
- the mouse button was pressed in an indicator or elsewhere, the
- action procedure you pass to TrackControl (or whose pointer you
- store in the control record) can be set up for only one case or
- the other. If you store a pointer to a default action procedure
- in a control record, be sure it will be used only when appropriate
- for that type of action procedure. The only way to specify actions
- in response to all mouse-down events in a control, regardless of
- whether they’re in an indicator, is via the control definition
- function.
-
- Assembly-language note: If you store a pointer to a procedure in the global
- variable DragHook, that procedure will be called
- repeatedly (with no parameters) for as long as the
- user holds down the mouse button. TrackControl
- invokes the Window Manager macro _DragTheRgn,
- which calls the DragHook procedure. _DragTheRgn
- uses the pattern stored in the global variable
- DragPattern for the dragged outline of the indicator.
-
- FUNCTION TestControl (theControl: ControlHandle; thePoint: Point) : INTEGER;
-
- If theControl is visible and active, TestControl tests which part of the control
- contains thePoint (in the local coordinates of the control’s window); it returns the
- corresponding part code, or 0 if the point is outside the control. If the control is
- invisible or inactive, TestControl returns 0. TestControl is called by FindControl
- and TrackControl; normally you won’t need to call it yourself.
-
- _______________________________________________________________________________
-
- »Control Movement and Sizing
-
- PROCEDURE MoveControl (theControl: ControlHandle; h,v: INTEGER);
-
- MoveControl moves theControl to a new location within its window. The top left corner
- of the control’s enclosing rectangle is moved to the horizontal and vertical coordinates
- h and v (given in the local coordinates of the control’s window); the bottom right
- corner is adjusted accordingly, to keep the size of the rectangle the same as before.
- If the control is currently visible, it’s hidden and then redrawn at its new location.
-
- PROCEDURE DragControl (theControl: ControlHandle; startPt: Point;
- limitRect,slopRect: Rect; axis: INTEGER);
-
- Called with the mouse button down inside theControl, DragControl pulls a dotted
- outline of the control around the screen, following the movements of the mouse until
- the button is released. When the mouse button is released, DragControl calls MoveControl
- to move the control to the location to which it was dragged.
-
- Note: Before beginning to follow the mouse, DragControl calls the control
- definition function to allow it to do its own “custom dragging” if
- it chooses. If the definition function doesn’t choose to do any
- custom dragging, DragControl uses the default method of dragging
- described here.
-
- The startPt, limitRect, slopRect, and axis parameters have the same meaning as for
- the Window Manager function DragGrayRgn. These parameters are reviewed briefly below;
- see the description of DragGrayRgn in the Window Manager chapter for more details.
-
- • StartPt is assumed to be the point where the mouse button was originally
- pressed, in the local coordinates of the control’s window.
- • LimitRect limits the travel of the control’s outline, and should normally
- coincide with or be contained within the window’s content region.
- • SlopRect allows the user some “slop” in moving the mouse; it should
- completely enclose limitRect.
- • The axis parameter allows you to constrain the control’s motion to
- only one axis. It has one of the following values:
-
- CONST noConstraint = 0; {no constraint}
- hAxisOnly = 1; {horizontal axis only}
- vAxisOnly = 2; {vertical axis only}
-
- Assembly-language note: Like TrackControl, DragControl invokes the
- macro _DragTheRgn, so you can use the global
- variables DragHook and DragPattern.
-
- PROCEDURE SizeControl (theControl: ControlHandle; w,h: INTEGER);
-
- SizeControl changes the size of theControl’s enclosing rectangle. The bottom right
- corner of the rectangle is adjusted to set the rectangle’s width and height to the
- number of pixels specified by w and h; the position of the top left corner is not
- changed. If the control is currently visible, it’s hidden and then redrawn in its new
- size.
-
- _______________________________________________________________________________
-
- »Control Setting and Range
-
- PROCEDURE SetCtlValue (theControl: ControlHandle; theValue: INTEGER);
-
- SetCtlValue sets theControl’s current setting to theValue and redraws the control to
- reflect the new setting. For check boxes and radio buttons, the value 1 fills the
- control with the appropriate mark, and 0 clears it. For scroll bars, SetCtlValue
- redraws the thumb where appropriate.
-
- If the specified value is out of range, it’s forced to the nearest endpoint of the
- current range (that is, if theValue is less than the minimum setting, SetCtlValue
- sets the current setting to the minimum; if theValue is greater than the maximum
- setting, it sets the current setting to the maximum).
-
- FUNCTION GetCtlValue (theControl: ControlHandle) : INTEGER;
-
- GetCtlValue returns theControl’s current setting.
-
- PROCEDURE SetCtlMin (theControl: ControlHandle; minValue: INTEGER);
-
- Assembly-language note: The macro you invoke to call SetCtlMin from
- assembly language is named _SetMinCtl.
-
- SetCtlMin sets theControl’s minimum setting to minValue and redraws the control to
- reflect the new range. If the control’s current setting is less than minValue, the
- setting is changed to the new minimum.
-
- FUNCTION GetCtlMin (theControl: ControlHandle) : INTEGER;
-
- Assembly-language note: The macro you invoke to call GetCtlMin from
- assembly language is named _GetMinCtl.
-
- GetCtlMin returns theControl’s minimum setting.
-
- PROCEDURE SetCtlMax (theControl: ControlHandle; maxValue: INTEGER);
-
- Assembly-language note: The macro you invoke to call SetCtlMax from
- assembly language is named _SetMaxCtl.
-
- SetCtlMax sets theControl’s maximum setting to maxValue and redraws the control to
- reflect the new range. If the control’s current setting is greater than maxValue, the
- setting is changed to the new maximum.
-
- Note: If you set the maximum setting of a scroll bar equal to its minimum
- setting, the control definition function will make the scroll bar
- inactive.
-
- FUNCTION GetCtlMax (theControl: ControlHandle) : INTEGER;
-
- Assembly-language note: The macro you invoke to call GetCtlMax from
- assembly language is named _GetMaxCtl.
-
- GetCtlMax returns theControl’s maximum setting.
-
- _______________________________________________________________________________
-
- »Miscellaneous Routines
-
- PROCEDURE SetCRefCon (theControl: ControlHandle; data: LONGINT);
-
- SetCRefCon sets theControl’s reference value to the given data.
-
- FUNCTION GetCRefCon (theControl: ControlHandle) : LONGINT;
-
- GetCRefCon returns theControl’s current reference value.
-
- PROCEDURE SetCtlAction (theControl: ControlHandle; actionProc: ProcPtr);
-
- SetCtlAction sets theControl’s default action procedure to actionProc.
-
- FUNCTION GetCtlAction (theControl: ControlHandle) : ProcPtr;
-
- GetCtlAction returns a pointer to theControl’s default action procedure, if any. (It
- returns whatever is in that field of the control record.)
-
- The following new Control Manager routines can be used as noted below for the Macintosh
- Plus, the Macintosh SE, and the Macintosh II.
-
- FUNCTION GetCVariant (theControl: ControlHandle) : INTEGER;
- [Macintosh Plus, Macintosh SE, and Macintosh II]
-
- The GetVariant function returns the variant control value for the control described
- by theControl. This value was formerly stored in the high four bits of the control
- defproc handle; for future compatibility, use the GetCVariant routine to access this
- value.
-
- PROCEDURE SetCtlColor (theControl: ControlHandle; newColorTable: CCTabHandle);
- [Macintosh II]
-
- The SetCtlColor procedure sets or modifies a control’s color table. If the control
- currently has no auxiliary control record, a new one is created with the given color
- table and added to the head of the auxiliary control list. If there is already an
- auxiliary record for the control, its color table is replaced by the contents of
- newColorTable.
-
- If newColorTable has the same contents as the default color table, the
- control’s existing auxiliary record and color table are removed from the auxiliary
- control list and deallocated. If theControl = NIL, the operation modifies the default
- color table itself. If the control is visible, it will be redrawn by SetCtlColor
- using the new color table.
-
- FUNCTION GetAuxCtl (theControl: ControlHandle;
- VAR acHndl: AuxCtlHandle) : BOOLEAN; [Macintosh II]
-
- The GetAuxCtl function returns a handle to a control’s AuxCtlRec:
-
- • If the given control has its own color table, the function returns TRUE.
- • If the control used the default color set, the function returns FALSE.
- • If the control asked to receive the default color set (theControl = NIL),
- then the function returns TRUE.
-
- _______________________________________________________________________________
-
-
- æKY Defining…Your…Own…Controls
- æC »DEFINING YOUR OWN CONTROLS
- _______________________________________________________________________________
-
- In addition to the standard, built-in control types (buttons, check boxes, radio
- buttons, and scroll bars), the Control Manager allows you to define
- “custom” control types of your own. Maybe you need a three-way selector switch, a
- memory-space indicator that looks like a thermometer, or a thruster control for a
- spacecraft simulator—whatever your application calls for. Controls and their indicators
- may occupy regions of any shape, in the full generality permitted by QuickDraw.
-
- To define your own type of control, you write a control definition function and store
- it in a resource file. When you create a control, you provide a control definition
- ID, which leads to the control definition function. The control definition ID is an
- integer that contains the resource ID of the control definition function in its upper
- 12 bits and a variation code in its lower four bits. Thus, for a given resource ID
- and variation code, the control definition ID is
-
- 16 * resource ID + variation code
-
- For example, buttons, check boxes, and radio buttons all use the standard definition
- function whose resource ID is 0, but they have variation codes of 0, 1, and 2, respectively.
-
- The Control Manager calls the Resource Manager to access the control definition
- function with the given resource ID. The Resource Manager reads the control definition
- function into memory and returns a handle to it. The Control Manager stores this
- handle in the contrlDefProc field of the control record. In 24-bit addressing mode,
- the variation code is placed in the high-order byte of this field; in 32-bit mode,
- the variation code is placed in the most significant byte of the acReserved field in
- the control’s AuxCtlRec. Later, when it needs to perform a type-dependent action on
- the control, it calls the control definition function and passes it the variation
- code as a parameter. Figure 7 illustrates this process.
-
- Keep in mind that the calls your application makes to use a control depend heavily on
- the control definition function. What you pass to the TrackControl function, for
- example, depends on whether the definition function contains an action procedure for
- the control. Just as you need to know how to call TrackControl for the standard
- controls, each custom control type will have a particular calling protocol that must
- be followed for the control to work properly.
-
- _______________________________________________________________________________
-
- »The Control Definition Function
-
- The control definition function is usually written in assembly language, but may be
- written in Pascal.
-
- •••Refer to Figure 7.•••
-
- Figure 7–Control Definition Handling
-
- Assembly-language note: The function’s entry point must be at the beginning.
-
- You can give your control definition function any name you like. Here’s how you would
- declare one named MyControl:
-
- FUNCTION MyControl (varCode: INTEGER; theControl: ControlHandle;
- message: INTEGER; param: LONGINT) : LONGINT;
-
- VarCode is the variation code, as described above.
-
- TheControl is a handle to the control that the operation will affect.
-
- The message parameter identifies the desired operation. It has one of the following
- values:
-
- CONST drawCntl = 0; {draw the control (or control part)}
- testCntl = 1; {test where mouse button was pressed}
- calcCRgns = 2; {calculate control's region (or indicator's)}
- initCntl = 3; {do any additional control initialization}
- dispCntl = 4; {take any additional disposal actions}
- posCntl = 5; {reposition control's indicator and update it}
- thumbCntl = 6; {calculate parameters for dragging indicator}
- dragCntl = 7; {drag control (or its indicator)}
- autoTrack = 8; {execute control's action procedure}
-
- As described below in the discussions of the routines that perform these operations,
- the value passed for param, the last parameter of the control definition function,
- depends on the operation. Where it’s not mentioned below, this parameter is ignored.
- Similarly, the control definition function is expected to return a function result
- only where indicated; in other cases, the function should return 0.
-
- In some cases, the value of param or the function result is a part code. The part
- code 128 is reserved for future use and shouldn’t be used for parts of your controls.
- Part codes greater than 128 should be used for indicators; however, 129 has special
- meaning to the control definition function, as described below.
-
- Note: “Routine” here doesn’t necessarily mean a procedure or function.
- While it’s a good idea to set these up as subprograms inside the
- control definition function, you’re not required to do so.
-
- A new version of the control definition function (version 4 or greater) in the 128K
- ROM allows buttons, check boxes, and radio buttons to have multiple lines of text in
- their titles. When specifying the title with either NewControl or SetCTitle, simply
- separate the lines with the ASCII character code $0D
- (carriage return). You can also use a version of the Resource Editor that supports
- the 128K ROM to specify multiline titles.
-
- Note: This feature will work with the 64K ROM if the new version of
- the control definition function is in the system resource file.
-
- If the control is a button, each line is horizontally centered and separated from the
- neighboring lines by the font’s leading. (Since the height of each line is equal to
- the ascent plus descent plus leading of the font used, be sure to make the total
- height of the enclosing rectangle greater than the number of lines times this height.)
-
- If the control is a check box or a radio button, the text is left-justified and the
- check box or button is vertically centered within the enclosing rectangle, cntrlRect.
-
- Note: The text is right-justified on check boxes and radio buttons if
- running under a non-Roman system that draws text from right-to-left.
- See the Script Manager chapter for more information.
- _______________________________________________________________________________
-
- »The Draw Routine
-
- The message drawCntl asks the control definition function to draw all or part of the
- control within its enclosing rectangle. The value of param is a part code specifying
- which part of the control to draw, or 0 for the entire control. If the control is
- invisible (that is, if its contrlVis field is 0), there’s nothing to do; if it’s
- visible, the definition function should draw it (or the requested part), taking into
- account the current values of its contrlHilite and contrlValue fields. The control
- may be either scaled or clipped to the enclosing rectangle.
-
- If param is the part code of the control’s indicator, the draw routine can assume
- that the indicator hasn’t moved; it might be called, for example, to highlight the
- indicator. There’s a special case, though, in which the draw routine has to allow for
- the fact that the indicator may have moved: This happens when the Control Manager
- procedures SetCtlValue, SetCtlMin, and SetCtlMax call the control definition function
- to redraw the indicator after changing the control setting. Since they have no way of
- knowing what part code you chose for your indicator, they all pass 129 to mean the
- indicator. The draw routine must detect this part code as a special case, and remove
- the indicator from its former location before drawing it.
-
- Note: If your control has more than one indicator, 129 should be
- interpreted to mean all indicators.
-
- _______________________________________________________________________________
-
- »The Test Routine
-
- The Control Manager function FindControl sends the message testCntl to the control
- definition function when the mouse button is pressed in a visible control. This
- message asks in which part of the control, if any, a given point lies. The point is
- passed as the value of param, in the local coordinates of the control’s window; the
- vertical coordinate is in the high-order word of the long integer and the horizontal
- coordinate is in the low-order word. The control definition function should return
- the part code for the part of the control that contains the point; it should return 0
- if the point is outside the control or if the control is inactive.
-
- _______________________________________________________________________________
-
- »The Routine to Calculate Regions
-
- The control definition function should respond to the message calcCRgns by calculating
- the region the control occupies within its window. Param is a QuickDraw region handle;
- the definition function should update this region to the region occupied by the
- control, expressed in the local coordinate system of its window.
-
- If the high-order bit of param is set, the region requested is that of the control’s
- indicator rather than the control as a whole. The definition function should clear
- the high bit of the region handle before attempting to update the region.
-
- _______________________________________________________________________________
-
- »The Initialize Routine
-
- After initializing fields as appropriate when creating a new control, the Control
- Manager sends the message initCntl to the control definition function. This gives the
- definition function a chance to perform any type-specific initialization it may
- require. For example, if you implement the control’s action procedure in its control
- definition function, you’ll set up the initialize routine to store POINTER(–1) in the
- contrlAction field; TrackControl calls for this control would pass POINTER(–1) in the
- actionProc parameter.
-
- The control definition function for scroll bars allocates space for a region to hold
- the scroll bar’s thumb and stores the region handle in the contrlData field of the
- new control record. The initialize routine for standard buttons, check boxes, and
- radio buttons does nothing.
-
- _______________________________________________________________________________
-
- »The Dispose Routine
-
- The Control Manager’s DisposeControl procedure sends the message dispCntl to the
- control definition function, telling it to carry out any additional actions required
- when disposing of the control. For example, the standard definition function for
- scroll bars releases the space occupied by the thumb region, whose handle is kept in
- the control’s contrlData field. The dispose routine for standard buttons, check
- boxes, and radio buttons does nothing.
-
- _______________________________________________________________________________
-
- »The Drag Routine
-
- The message dragCntl asks the control definition function to drag the control or its
- indicator around on the screen to follow the mouse until the user releases the mouse
- button. Param specifies whether to drag the indicator or the whole control: 0 means
- drag the whole control, while a nonzero value means drag only the indicator.
-
- The control definition function need not implement any form of “custom
- dragging”; if it returns a result of 0, the Control Manager will use its own default
- method of dragging (calling DragControl to drag the control or the Window Manager
- function DragGrayRgn to drag its indicator). Conversely, if the control definition
- function chooses to do its own custom dragging, it should signal the Control Manager
- not to use the default method by returning a nonzero result.
-
- If the whole control is being dragged, the definition function should call MoveControl
- to reposition the control to its new location after the user releases the mouse
- button. If just the indicator is being dragged, the definition function should execute
- its own position routine (see below) to update the control’s setting and redraw it in
- its window.
-
- _______________________________________________________________________________
-
- »The Position Routine
-
- For controls that don’t use the Control Manager’s default method of dragging the
- control’s indicator (as performed by DragGrayRgn), the control definition function
- must include a position routine. When the mouse button is released inside the indicator
- of such a control, TrackControl calls the control definition function with the message
- posCntl to reposition the indicator and update the control’s setting accordingly. The
- value of param is a point giving the vertical and horizontal offset, in pixels, by
- which the indicator is to be moved relative to its current position. (Typically, this
- is the offset between the points where the user pressed and released the mouse button
- while dragging the indicator.) The vertical offset is given in the high-order word of
- the long integer and the horizontal offset in the low-order word. The definition
- function should calculate the control’s new setting based on the given offset, update
- the contrlValue field, and redraw the control within its window to reflect the new
- setting.
-
- Note: The Control Manager procedures SetCtlValue, SetCtlMin, and SetCtlMax
- do not call the control definition function with this message; instead,
- they pass the drawCntl message to execute the draw routine (see above).
-
- _______________________________________________________________________________
-
- »The Thumb Routine
-
- Like the position routine, the thumb routine is required only for controls that don’t
- use the Control Manager’s default method of dragging the control’s indicator. The
- control definition function for such a control should respond to the message thumbCntl
- by calculating the limiting rectangle, slop rectangle, and axis constraint for dragging
- the control’s indicator. Param is a pointer to the following data structure:
-
- RECORD
- limitRect,slopRect: Rect;
- axis: INTEGER
- END;
-
- On entry, param^.limitRect.topLeft contains the point where the mouse button was
- first pressed. The definition function should store the appropriate values into the
- fields of the record pointed to by param; they’re analogous to the similarly named
- parameters to DragGrayRgn.
-
- _______________________________________________________________________________
-
- »The Track Routine
-
- You can design a control to have its action procedure in the control definition
- function. To do this, set up the control’s initialize routine to store
- POINTER(–1) in the contrlAction field of the control record, and pass
- POINTER(–1) in the actionProc parameter to TrackControl. TrackControl will respond by
- calling the control definition function with the message autoTrack. The definition
- function should respond like an action procedure, as discussed in detail in the
- description of TrackControl. It can tell which part of the control the mouse button
- was pressed in from param, which contains the part code. The track routine for each
- of the standard control types does nothing.
-
- _______________________________________________________________________________
-
-
- æKY Formats…of…Resources…for…Controls
- æC »FORMATS OF RESOURCES FOR CONTROLS
- _______________________________________________________________________________
-
- The GetNewControl function takes the resource ID of a control template as a parameter,
- and gets from that template the same information that the NewControl function gets
- from eight of its parameters. The resource type for a control template is 'CNTL', and
- the resource data has the following format:
-
- Number of bytes Contents
-
- 8 bytes Same as boundsRect parameter to NewControl
- 2 bytes Same as value parameter to NewControl
- 2 bytes Same as visible parameter to NewControl
- 2 bytes Same as max parameter to NewControl
- 2 bytes Same as min parameter to NewControl
- 2 bytes Same as procID parameter to NewControl
- 4 bytes Same as refCon parameter to NewControl
- n bytes Same as title parameter to NewControl
- (1-byte length in bytes, followed by the
- characters of the title)
-
- The resource type for a control definition function is 'CDEF'. The resource data is
- simply the compiled or assembled code of the function.
-
- _______________________________________________________________________________
-
-
- æKY Summary…of…the…Control…Manager
- æC »SUMMARY OF THE CONTROL MANAGER
- _______________________________________________________________________________
-
- Constants
-
- CONST
-
- { Control definition IDs }
-
- pushButProc = 0; {simple button}
- checkBoxProc = 1; {check box}
- radioButProc = 2; {radio button}
- useWFont = 8; {add to above to use window's font}
- scrollBarProc = 16; {scroll bar}
-
- { Part codes }
-
- inButton = 10; {simple button}
- inCheckBox = 11; {check box or radio button}
- inUpButton = 20; {up arrow of a scroll bar}
- inDownButton = 21; {down arrow of a scroll bar}
- inPageUp = 22; {"page up" region of a scroll bar}
- inPageDown = 23; {"page down" region of a scroll bar}
- inThumb = 129; {thumb of a scroll bar}
-
- { Axis constraints for DragControl }
-
- noConstraint = 0; {no constraint}
- hAxisOnly = 1; {horizontal axis only}
- vAxisOnly = 2; {vertical axis only}
-
- { Messages to control definition function }
-
- drawCntl = 0; {draw the control (or control part)}
- testCntl = 1; {test where mouse button was pressed}
- calcCRgns = 2; {calculate control's region (or indicator's)}
- initCntl = 3; {do any additional control initialization}
- dispCntl = 4; {take any additional disposal actions}
- posCntl = 5; {reposition control's indicator and update it}
- thumbCntl = 6; {calculate parameters for dragging indicator}
- dragCntl = 7; {drag control (or its indicator)}
- autoTrack = 8; {execute control's action procedure}
-
- { Control part colors }
-
- cFrameColor = 0;
- cBodyColor = 1;
- cTextColor = 2;
- cThumbColor = 3;
-
- _______________________________________________________________________________
-
- Data Types
-
- TYPE
- ControlPtr = ^ControlRecord;
- ControlHandle = ^ControlPtr;
- ControlRecord =
- PACKED RECORD
- nextControl: ControlHandle; {next control}
- contrlOwner: WindowPtr; {control's window}
- contrlRect: Rect; {enclosing rectangle}
- contrlVis: Byte; {255 if visible}
- contrlHilite: Byte; {highlight state}
- contrlValue: INTEGER; {control's current setting}
- contrlMin: INTEGER; {control's minimum setting}
- contrlMax: INTEGER; {control's maximum setting}
- contrlDefProc: Handle; {control definition function}
- contrlData: Handle; {data used by contrlDefProc}
- contrlAction: ProcPtr; {default action procedure}
- contrlRfCon: LONGINT; {control's reference value}
- contrlTitle: Str255 {control's title}
- END;
-
- AuxCtlHandle = ^AuxCtlPtr;
- AuxCtlPtr = ^AuxCtlRec;
- AuxCtlRec = RECORD
- acNext: AuxCtlHandle; {handle to next record in list}
- acOwner: ControlHandle; {handle to owning control}
- acCTable: CCTabHandle; {handle to control's color }
- { table}
- acFlags: INTEGER; {miscellaneous flags; reserved}
- acReserved: LONGINT; {reserved for future expansion}
- acRefCon: LONGINT {reserved for application use}
- END;
-
- CCTabHandle = ^CCTabPtr;
- CCTabPtr = ^CtlCTab;
- CtlCTab = RECORD
- ccSeed: LONGINT; {not used for controls}
- ccRider: INTEGER; {not used for controls}
- ctSize: INTEGER; {number of entries in table –1}
- ctTable: cSpecArray {array of ColorSpec records}
- END;
-
- _______________________________________________________________________________
-
- Routines
-
- Initialization and Allocation
-
- FUNCTION NewControl (theWindow: WindowPtr; boundsRect: Rect;
- title: Str255; visible: BOOLEAN; value: INTEGER;
- min,max: INTEGER; procID: INTEGER;
- refCon: LONGINT) : ControlHandle;
- FUNCTION GetNewControl (controlID: INTEGER;
- theWindow: WindowPtr) : ControlHandle;
- PROCEDURE DisposeControl (theControl: ControlHandle);
- PROCEDURE KillControls (theWindow: WindowPtr);
-
- Control Display
-
- PROCEDURE SetCTitle (theControl: ControlHandle; title: Str255);
- PROCEDURE GetCTitle (theControl: ControlHandle; VAR title: Str255);
- PROCEDURE HideControl (theControl: ControlHandle);
- PROCEDURE ShowControl (theControl: ControlHandle);
- PROCEDURE DrawControls (theWindow: WindowPtr);
- PROCEDURE Draw1Control (theControl: ControlHandle); [128K ROM]
- PROCEDURE UpdtControl (theWindow: WindowPtr;
- updateRgn: RgnHandle); [128K ROM]
- PROCEDURE HiliteControl (theControl: ControlHandle; hiliteState: INTEGER);
-
- Mouse Location
-
- FUNCTION FindControl (thePoint: Point; theWindow: WindowPtr;
- VAR whichControl: ControlHandle) : INTEGER;
- FUNCTION TrackControl (theControl: ControlHandle; startPt: Point;
- actionProc: ProcPtr) : INTEGER;
- FUNCTION TestControl (theControl: ControlHandle;
- thePoint: Point) : INTEGER;
-
- Control Movement and Sizing
-
- PROCEDURE MoveControl (theControl: ControlHandle; h,v: INTEGER);
- PROCEDURE DragControl (theControl: ControlHandle; startPt: Point;
- limitRect,slopRect: Rect; axis: INTEGER);
- PROCEDURE SizeControl (theControl: ControlHandle; w,h: INTEGER);
-
- Control Setting and Range
-
- PROCEDURE SetCtlValue (theControl: ControlHandle; theValue: INTEGER);
- FUNCTION GetCtlValue (theControl: ControlHandle) : INTEGER;
- PROCEDURE SetCtlMin (theControl: ControlHandle; minValue: INTEGER);
- FUNCTION GetCtlMin (theControl: ControlHandle) : INTEGER;
- PROCEDURE SetCtlMax (theControl: ControlHandle; maxValue INTEGER);
- FUNCTION GetCtlMax (theControl: ControlHandle) : INTEGER;
-
- Miscellaneous Routines
-
- PROCEDURE SetCRefCon (theControl: ControlHandle; data: LONGINT);
- FUNCTION GetCRefCon (theControl: ControlHandle) : LONGINT;
- PROCEDURE SetCtlAction (theControl: ControlHandle; actionProc ProcPtr);
- FUNCTION GetCtlAction (theControl: ControlHandle) : ProcPtr;
- PROCEDURE SetCtlColor (theControl: ControlHandle;
- newColorTable: CCTabHandle);
- FUNCTION GetAuxCtl (theControl: ControlHandle;
- VAR acHndl: AuxWinHandle): BOOLEAN;
- FUNCTION GetCVariant (theControl: ControlHandle) : INTEGER;
-
- _______________________________________________________________________________
-
- Action Procedure for TrackControl
-
- If an indicator: PROCEDURE MyAction;
- If not an indicator: PROCEDURE MyAction (theControl: ControlHandle;
- partCode: INTEGER);
-
- _______________________________________________________________________________
-
- Control Definition Function
-
- FUNCTION MyControl (varCode: INTEGER; theControl: ControlHandle;
- message: INTEGER; param: LONGINT) : LONGINT;
-
- _______________________________________________________________________________
-
- Global Variables
-
- AuxWinHead Contains a pointer to the linked list of auxiliary
- control records.
-
- _______________________________________________________________________________
-
- Assembly-Language Information
-
- Constants
-
- ; Control definition IDs
-
- pushButProc .EQU 0 ;simple button
- checkBoxProc .EQU 1 ;check box
- radioButProc .EQU 2 ;radio button
- useWFont .EQU 8 ;add to above to use window's font
- scrollBarProc .EQU 16 ;scroll bar
-
- ; Part codes
-
- inButton .EQU 10 ;simple button
- inCheckBox .EQU 11 ;check box or radio button
- inUpButton .EQU 20 ;up arrow of a scroll bar
- inDownButton .EQU 21 ;down arrow of a scroll bar
- inPageUp .EQU 22 ;"page up" region of a scroll bar
- inPageDown .EQU 23 ;"page down" region of a scroll bar
- inThumb .EQU 129 ;thumb of a scroll bar
-
- ; Axis constraints for DragControl
-
- noConstraint .EQU 0 ;no constraint
- hAxisOnly .EQU 1 ;horizontal axis only
- vAxisOnly .EQU 2 ;vertical axis only
-
- ; Messages to control definition function
-
- drawCtlMsg .EQU 0 ;draw the control (or control part)
- hitCtlMsg .EQU 1 ;test where mouse button was pressed
- calcCtlMsg .EQU 2 ;calculate control's region (or indicator's)
- newCtlMsg .EQU 3 ;do any additional control initialization
- dispCtlMsg .EQU 4 ;take any additional disposal actions
- posCtlMsg .EQU 5 ;reposition control's indicator and update it
- thumbCtlMsg .EQU 6 ;calculate parameters for dragging indicator
- dragCtlMsg .EQU 7 ;drag control (or its indicator)
- trackCtlMsg .EQU 8 ;execute control's action procedure
-
- ;auxCtlRec structure
-
- acnext EQU $0 ;[handle] next in chain
- acOwner EQU $4 ;[ControlHandle] owner ID
- acCTable EQU $8 ;[CTabHandle] color table
- acFlags EQU $C ;[word] miscellaneous flags
- acReserved EQU $E ;[LONGINT] for expansion
- acRefCon EQU $18 ;[LONGINT] user constant
- auxWinSize EQU $1C ;size of record
-
- ; Equates for the colors of control parts
-
- cFrameColor EQU 0
- cBodyColor EQU 1
- cTextColor EQU 2
- cThumbColor EQU 3
-
- ; Global variable
-
- AuxCtlHead EQU $0CD4 ;Control Aux List head
-
- Control Record Data Structure
-
- nextControl Handle to next control in control list
- contrlOwner Pointer to this control’s window
- contrlRect Control’s enclosing rectangle (8 bytes)
- contrlVis 255 if control is visible (byte)
- contrlHilite Highlight state (byte)
- contrlValue Control’s current setting (word)
- contrlMin Control’s minimum setting (word)
- contrlMax Control’s maximum setting (word)
- contrlDefHandle Handle to control definition function
- contrlData Data used by control definition function (long)
- contrlAction Address of default action procedure
- contrlRfCon Control’s reference value (long)
- contrlTitle Handle to control’s title (preceded by length byte)
- contrlSize Size in bytes of control record except contrlTitle field
-
- Special Macro Names
-
- Pascal name Macro name
-
- DisposeControl _DisposControl
- GetCtlMax _GetMaxCtl
- GetCtlMin _GetMinCtl
- SetCtlMax _SetMaxCtl
- SetCtlMin _SetMinCtl
-
- Variables
-
- DragHook Address of procedure to execute during TrackControl
- and DragControl
- DragPattern Pattern of dragged region’s outline (8 bytes)
-
- Further Reference:
- _______________________________________________________________________________
- Resource Manager
- QuickDraw
- Toolbox Event Manager
- Window Manager
- Script Manager
- Technical Note #196, 'CDEF' Parameters and Bugs
- Technical Note #212, The Joy Of Being 32-Bit Clean
-
- æKY ControlPanels
- æC
- _______________________________________________________________________________
-
- CONTROL PANELS
- _______________________________________________________________________________
-
- About…the…Control…Panels…Chapter
- About…Control…Panels
- About…the…Monitors…Control…Panel
- Writing…Control…Panel…Files
- Designing…an…Extension…for…the…Monitors…Control…Panel
- Contents…of…an…Extension…File…for…the…Monitors…Control…Panel
- 'card'…Resource
- 'mntr'…Resource
- The…Mntr…Function
- Messages…to…the…Mntr…Function
- Error-Handling…by…the…Mntr…Function
- 'DITL'…Resource
- 'RECT'…Resource
- 'ICON'…and…'cicn'…Resources
- 'STR#'…Resource
- 'gama'…Resources
- 'FREF',…'BNDL',…'ICN#',…and…Owner…Resources
- 'INIT'…Resource
- Sample…of…a…File…That…Extends…the…Monitors…Control…Panel
- Including…Another…Control…Panel…Definition…in…a…Monitors…Extension
- Summary…of…the…Extension…File…for…the…Monitors…Control…Panel
- Control…Panels…Constants
- Control…Panels…Routines
- _______________________________________________________________________________
-
-
-
- æKY About…the…Control…Panels…Chapter
- æC »ABOUT THIS CHAPTER Control Panels
- _______________________________________________________________________________
-
- All versions of the Macintosh Operating System previous to system software
- version 7.0 provide a desk accessory called the Control Panel. The Control Panel
- allows users to control certain system features, such as speaker volume, date
- and time, and desktop pattern. With the release of System file version 4.1,
- documented in Volume V, the Control Panel became extensible by the addition of
- control panel extension files (files of file type 'cdev') to the System Folder.
- The contents and operation of control panel extension files are described in the
- Control Panel chapter of Volume V.
-
- In system software version 7.0, the Control Panel, as a discrete desk accessory,
- has been eliminated. Instead, the Finder can now open each file of file type
- 'cdev'. The panel defined by the control panel file, which had been part of the
- Control Panel, is now an independent dialog box.
-
- This chapter describes how to write a control panel file that is compatible with
- both the old Control Panel and with version 7.0, and how to write an extension
- for the Monitors control panel file.
-
- In this chapter, the dialog box defined by a file of file type 'cdev' is
- referred to as a control panel (as opposed to the Control Panel), and the file
- itself is referred to as a control panel file.
-
- Only the manufacturer of a video device should write an extension to the
- Monitors control panel for that device. Therefore, if you are not developing a
- video card for the Macintosh computer, you do not need the information in this
- chapter on the Monitors control panel.
-
- _______________________________________________________________________________
-
- æKY About…Control…Panels
- æC »ABOUT CONTROL PANELS Control Panels
- _______________________________________________________________________________
-
- Under system software version 7.0, the user sees little difference between a
- control panel and a small application. The main reason to create a control panel
- file rather than an application is to maintain compatibility with the Control
- Panel for users who are using older operating systems. Any control panel file
- that follows the rules and suggestions given in the Control Panel chapter of
- Volume V will continue to work without problems under version 7.0.
- Control panels open in the Finder layer. The user can store control panels in
- either the Control Panels folder, the Apple Menu folder in the System Folder, or
- any other location in the file system.
-
- You should refer to a file of type 'cdev' as a control panel file in any user
- documentation that you provide. Don’t pass on the file type name of this file or
- any other file to users.
- _______________________________________________________________________________
-
- æKY About…the…Monitors…Control…Panel
- æC »ABOUT THE MONITORS CONTROL PANEL Control Panels
- _______________________________________________________________________________
-
- The Monitors control panel file that is provided with system software version
- 7.0 is extensible. The developer of a video card can add items to the Monitors
- control panel that allow users to control features of the video device.
-
- The Monitors control panel file displays a control panel that allows a user to
-
- • select which one of the monitors connected to the system should display
- the menu bar
- • select which monitor the system should use as a startup screen
- • inform the Operating System about the relative locations of the monitors
- • control some features of the monitors, such as whether a color monitor
- displays in color or in black and white, or the number of colors or
- gray-scale values to display
-
- Figure 9-1 shows an example of the Monitors control panel.
-
- ø 9.1 The Monitors control panel
-
- As Figure 9-1 illustrates, the Monitors control panel now includes a button
- labeled Options; when the user clicks this button, another panel appears with
- additional controls. When you add an extension to the Monitors control panel,
- the controls you add appear in the Options dialog box. Figure 9-2 shows an
- example of an Options dialog box for the Monitors control panel.
-
- ø 9.2 A sample Options dialog box for a Monitors control panel
-
- _______________________________________________________________________________
-
- æKY Writing…Control…Panel…Files
- æC »WRITING CONTROL PANEL FILES Control Panels
- _______________________________________________________________________________
-
- You should keep the following points in mind if you are writing or modifying a
- control panel file:
-
- • A control panel file displays a modeless dialog box with no menu bar. You
- can use the editing functions in the menu bar put up by the Finder if
- necessary, but you cannot add any menu choices. The Finder passes
- messages to your cdev function for the following standard selections from
- the Edit menu: undo, cut, copy, paste, and clear. Your cdev function can
- respond to these messages when it is appropriate to do so; for example,
- if your control panel has an editable input field, you can respond to
- these editing functions when the cursor is within this field.
-
- • The rectangles defined by the 'nrct' resource are no longer restricted to
- the size of the Control Panel; however, to maintain compatibility with
- previous operating systems, the rectangles’ coordinates should not exceed
- (–1, 87, 255, 322).
-
- • There is no longer a guarantee that the resources provided by the Control
- Panel are available when your control panel file is running. If your
- control panel file uses any Control Panel resources, it might not run
- under version 7.0. If your control panel file strictly follows the
- specifications in the Control Panel chapter of Volume V, however, it
- should run with no difficulty under version 7.0.
-
- • Your control panel file can continue to use the CPDialog parameter passed
- to the cdev function to obtain the dialog items list and the numItems
- parameter to determine the number of items in the dialog items list. If
- you use these parameters in your control panel file to gain access to the
- items in your dialog items list, your control panel file will operate
- correctly with both the Control Panel and the Finder. If you assume some
- value for the numItems parameter, however, your control panel file will
- not operate correctly in both situations. Dialog items lists are
- described in the Dialog Manager chapter of Volume I.
-
- • If the 'mach' resource in your control panel file indicates that the cdev
- function cannot run, the Finder displays an error message for the user
- and does not open the control panel file. In contrast, the Control Panel
- does not display the icon for a control panel file if the 'mach' resource
- indicates the cdev function cannot run. If your control panel file can
- run on all Macintosh computers, set the 'mach' resource to $FFFF 0000. If
- your control panel file can run only if certain hardware or software are
- present, set the 'mach' resource to $0000 FFFF. In the latter case, the
- Finder calls your cdev function with the message parameter set to macDev
- (8). Your cdev function should then call the Gestalt function to
- determine the software and hardware configuration of the machine. If your
- control panel file cannot run, return a result code of 0; if your control
- panel file can run, return a result code of 1. The Gestalt function is
- described in the Compatibility Guidelines chapter.
-
- • Result codes returned by your cdev function are now handled by the
- Finder. Whereas the Control Panel grays out the icon for a control panel
- file in response to certain result codes, the Finder displays an error
- message but does not gray out the control panel file icon.
-
- _______________________________________________________________________________
-
- æKY Designing…an…Extension…for…the…Monitors…Control…Panel
- æC »DESIGNING AN EXTENSION FOR THE MONITORS CONTROL PANEL Control Panels
- _______________________________________________________________________________
-
- The maker of a video card can provide a file of type 'cdev' that adds controls
- to the Options dialog box. An extension to the Monitors control panel should
- control features of the video card only; a Monitors extension should not control
- system features. For example, a Monitors control panel extension might allow the
- user to set the virtual screen size for a single monitor, but not to set the
- size of the menu bar, which can appear on any monitor.
-
- Because the Options dialog box is called from another dialog box, it is not
- advisable to write an extension that puts up yet another dialog box. If the
- features that you want to implement require an extensive or complex set of
- controls, it would be better to write a small application rather than an
- extension to the Monitors control panel file.
-
- † Warning: Only the manufacturer of the video card should write an extension
- to the Monitors control panel file. There can be only one extension to the
- Monitors control panel file for each video card. Apple Computer, Inc., reserves
- the right to write control panel files for its own video cards. Ê
- _______________________________________________________________________________
-
- æKY Contents…of…an…Extension…File…for…the…Monitors…Control…Panel
- æC »Contents of an Extension File for the Monitors Control Panel Control Panels
- _______________________________________________________________________________
-
- The extension file for the Monitors control panel must be a file of type 'cdev'
- containing at least the following resources:
-
- • 'card' (ID can be any number from –4080 through –4065)
- • 'mntr' (ID = –4096)
- • 'DITL' (ID = –4096)
- • 'RECT' (ID = –4096)
-
- Your Monitors extension file can also include any of the following resources:
-
- • 'ICON' (ID = –4096)
- • 'cicn' (ID = –4096)
- • 'STR#' (ID = –4096)
- • 'gama' (ID can be any number from –4080 through –4065)
- • 'FREF'
- • 'BNDL'
- • 'ICN#'
- • 'INIT'
- • owner resource
-
- These resources are described in the following sections. You can use resource ID
- numbers of –4080 through –4065 for any private resources in your Monitors
- extension.
-
- _______________________________________________________________________________
-
- æKY 'card'…Resource
- æC »'card' Resource Control Panels
- _______________________________________________________________________________
-
- The 'card' resource contains a Pascal string (that is, a length byte followed by
- an ASCII string) identical to the name of a video card as returned by the Slot
- Manager’s SReadDrvrName function (minus the period that the Slot Manager
- prefixes to the name). The extension file can contain as many 'card' resources
- as you wish, so that one extension file can handle several versions of one video
- card. The Options dialog box displays the name in the 'card' resource unless you
- also include a 'STR#' resource in the extension file, as described in “'STR#'
- Resource” later in this chapter. The Slot Manager chapter in Volume V describes
- the SReadDrvrName function.
-
- _______________________________________________________________________________
-
- æKY 'mntr'…Resource
- æC »'mntr' Resource Control Panels
- _______________________________________________________________________________
-
- The 'mntr' resource contains the code that carries out the functions of your
- Monitors extension. This resource must begin with a Mntr function that you must
- provide. The parameters passed to the Mntr function by the Monitors control
- panel allow your code to determine what action to perform. You can use the
- function result to keep a handle to local storage or to return an error code.
- These options are described in the sections “Parameter Descriptions” and
- “Error-Handling by the Mntr Function,” later in this chapter.
-
- _______________________________________________________________________________
-
- æKY The…Mntr…Function
- æC »The Mntr Function Control Panels
- _______________________________________________________________________________
-
- The 'mntr' resource must contain a function, referred to as a Mntr function, to
- respond to the various events that can occur while the Options dialog box is on
- the screen. The Mntr function is defined as follows:
-
- FUNCTION Mntr (message, item, numItems: Integer; monitorValue: LongInt;
- mDialog: DialogPtr; theEvent: EventRecord;
- screenNum: Integer; VAR screens: ScrnRsrcHandle;
- VAR scrnChanged: Boolean) : LongInt;
-
- Parameters
-
- message
- A message number, from the list defined in the following section “Messages,”
- that the Mntr function can use to determine what action to take.
-
- item
- When the message parameter equals StartupMsg, indicates whether the user is a
- superuser; that is, whether the user can be assumed to be very knowledgeable. If
- the user is a superuser, the item parameter is 1, if not, it is 0.
-
- For other values of the message parameter, the item parameter is the dialog item
- list number of the item on which the user clicked. To calculate the number in
- your 'DITL' resource, subtract the number passed in the numItems parameter from
- the number in the item parameter.
-
- numItems
- The dialog-item-list number of the last item in the Monitors control panel.
-
- monitorValue
- The result returned by the Mntr function the last time it was called. Because
- control panel routines cannot have global variables, you might want to use the
- function result to return a handle to the storage of your local data. This
- handle is then available in the monitorValue parameter the next time the Mntr
- function is called. The first time the function is called, monitorValue is 0.
-
- mDialog
- The dialog pointer for the Options dialog box. Dialog pointers are described in
- the Dialog Manager chapter of Volume I.
-
- theEvent
- The event record for an event that caused a hitMsg, nulMsg, or keyEvtMsg
- message. See the Toolbox Event Manager chapter of this volume for a discussion
- of event records.
-
- screenNum
- The number of the screen device (that is, the monitor) that the user has
- selected. Monitors are numbered consecutively, in the same order as the slots in
- which the cards are installed, starting with 1.
-
- screens
- A handle to the 'scrn' resource. The 'scrn' resource is described in the
- Graphics Devices chapter of Volume V.
-
- scrnChanged
- A Boolean value that you can use to indicate whether you have modified the
- 'scrn' resource. Set this parameter to TRUE if you have modified the 'scrn'
- resource. When ScrnChanged is TRUE, the Monitors control panel checks the 'scrn'
- resource to make sure that the values in it are still valid; if there is a
- problem, the Monitors control panel tries to correct it.
-
- This parameter is designed to make it easier for developers to implement a
- control that changes the apparent area displayed on the screen. For example,
- your monitor might be able to display either two pages of a document or a
- magnified view of a single page. If the user changes the area displayed on one
- screen in a system with multiple screens, the displays on adjacent screens could
- overlap or show gaps. When you change the 'scrn' resource to implement this
- change, the coordinates of the global rectangles for adjacent screens are no
- longer contiguous. In this case, if you have set the ScrnChanged parameter to
- TRUE, the Monitors control panel shifts the virtual locations of the screens to
- eliminate the gaps or overlaps.
-
- The result returned by the Mntr function can be either an error code or a value
- that you want to have available the next time the Monitors extension is called.
- Each time the extension is called, the monitorValue parameter contains the value
- that the Mntr function returned the last time it was called. See also
- “Error-Handling by the Mntr Function” later in this chapter.
-
- _______________________________________________________________________________
-
- æKY Messages…to…the…Mntr…Function
- æC »Messages to the Mntr Function Control Panels
- _______________________________________________________________________________
-
- The message passed as a parameter to the Mntr function can have any of the
- following values:
-
- CONST
- initMsg = 1; {initialization}
- okMsg = 2; {user clicked on OK button}
- cancelMsg = 3; {user clicked on CANCEL button}
- hitMsg = 4; {user clicked on control in Options dialog}
- nulMsg = 5; {periodic event}
- updateMsg = 6; {update event}
- activateMsg = 7; {not used}
- deactivateMsg = 8; {not used}
- keyEvtMsg = 9; {keyboard event}
- superMsg = 10; {show superuser controls}
- normalMsg = 11; {show only normal controls}
- startupMsg = 12; {code has been loaded}
-
- Messages
-
- initMsg
- Sent before the Options dialog box is displayed, when the Monitors control panel
- is first called. When you receive this message you should execute initialization
- code. You can use initialization code to set default values for controls and
- allocate memory for local storage, for example.
-
- If you do allocate storage, be sure to pass a handle to the storage as the
- function result. The next time your extension is called, this value will be
- available in the monitorValue parameter.
-
- okMsg
- The user has clicked the OK button. The OK button is a standard control put up
- by the Monitors control panel. You should not make any changes irreversible
- until this message is received.
-
- cancelMsg
- The user has clicked the Cancel button. The Cancel button is a standard control
- put up by the Monitors control panel. Return the system to the condition it was
- in before the user clicked the Options button, and terminate the Mntr function.
-
- hitMsg
- The user has clicked an enabled control in the Options dialog box. The
- dialog-item-list number of the control is passed in the Item parameter to the
- Mntr function; see the preceding section for a discussion of this parameter.
-
- nulMsg
- Sent periodically to allow you to perform tasks that have to be done repeatedly,
- such as blinking an insertion point. Do not assume any particular timing for
- this message.
-
- updateMsg
- Sent on every update event.
-
- activateMsg
- Because the Options dialog box is modal, this message is not used.
-
- deactivateMsg
- Because the Options dialog box is modal, this message is not used.
-
- keyEvtMsg
- Sent on every keyboard event.
-
- superMsg
- The user is a superuser; that is, the user can be assumed to be very
- knowledgeable. This message is sent when the user holds down the Option key
- while clicking on the Options button, and could be sent by other mechanisms in
- the future. You should display any controls that you have reserved for such
- users.
-
- normalMsg
- Do not display controls reserved for knowledgeable users.
-
- startupMsg
- Sent as soon as the code in your 'mntr' resource has been loaded, before the
- Monitors control panel finds any resources referred to by your Mntr function.
- You can then load and modify any resources that must allow for the capabilities
- of the system or for whether the user is a superuser. You can call the Gestalt
- function to determine the capabilities of the system and you can check the value
- of the item parameter in the Mntr function call to determine whether the user is
- a superuser. You can use this message, for example, to modify your 'DITL'
- resource to display special controls for superusers.
-
- _______________________________________________________________________________
-
- æKY Error-Handling…by…the…Mntr…Function
- æC »Error-Handling by the Mntr Function Control Panels
- _______________________________________________________________________________
-
- If an error occurs, your Mntr function should display an error dialog box and
- then return a value between 1 and 255. If your code returns a value in this
- range, the Monitors control panel closes the Options dialog box immediately and
- no more calls are made to your code. If your code returns an error in response
- to the InitMsg message, the Monitors control panel does not display the Options
- dialog box. You can display an alert describing the error before returning
- control to the Monitors control panel.
-
- _______________________________________________________________________________
-
- æKY 'DITL'…Resource
- æC »'DITL' Resource Control Panels
- _______________________________________________________________________________
-
- The 'DITL' resource is a standard dialog item list, as described in the Dialog
- Manager chapters of Volumes I and V. For an example of this resource, see
- “Sample of a File That Extends the Monitors Control Panel,” later in this
- chapter.
-
- _______________________________________________________________________________
-
- æKY 'RECT'…Resource
- æC »'RECT' Resource Control Panels
- _______________________________________________________________________________
-
- The 'RECT' resource describes the size and shape of the area taken up by your
- controls. Assume that the origin (that is, the top left corner) of the local
- coordinate system for your dialog items is at (0,0). (In this coordinate system,
- the Options dialog items put on the screen by the Monitors control panel would
- have a right edge at 319 and a negative top coordinate.) The Monitors control
- panel places your controls so that they start immediately below the standard
- Options controls (see Figure 9-2).
-
- Because the Monitors control panel transforms the coordinates of your controls
- to the coordinate system used by the Options dialog box, you must use the
- GetDItem procedure (described in the Dialog Manager chapter of Volume I) to get
- the true locations of your dialog items.
-
- If you want your controls to appear to be extensions of the standard controls
- put up by the Monitors control panel, start them immediately below the standard
- controls. If you want to separate your controls from the standard controls, draw
- a line across the screen below the standard controls. You can draw the line by
- making it a separate dialog item of type userItem. The procedure for the dialog
- item should consist of a FrameRect procedure that draws a one-pixel-high
- rectangle with coordinates of (2,1,3,319). Notice that these coordinates are
- relative to the standard controls displayed by the Monitors control panel; the
- control panel always places your controls below the standard controls. Dialog
- items are discussed in the Dialog Manager chapter of Volume I, and the FrameRect
- procedure is described in the QuickDraw chapter of Volume I.
-
- Figures 9-3 and 9-4 illustrate these two styles of Options dialog boxes. Figure
- 9-3 shows an Options dialog box to which the Monitors extension file has added
- buttons directly beneath the Cancel button in the standard dialog box. Figure
- 9-4 shows an Options dialog box to which the Monitors extension file has added
- buttons beneath a line separating the extended controls from the standard
- controls.
-
- ø 9.3 Monitors Option Dialog Box With Added Controls as Extensions of Standard
- Controls
-
- ø 9.4 Monitors Option Dialog Box With Added Controls Separate From Standard
- Controls
-
- _______________________________________________________________________________
-
- æKY 'ICON'…and…'cicn'…Resources
- æC »'ICON' and 'cicn' Resources Control Panels
- _______________________________________________________________________________
-
- The 'ICON' resource, described in the Resource Manager chapter of this volume,
- defines a black-and-white icon. The 'cicn' resource, described in the Color
- QuickDraw chapter of Volume V, defines a color icon. If you include either of
- these resources in the Monitors extension file, the icon is displayed in the
- Options dialog box of the Monitors control panel (Figure 9-2).
-
- _______________________________________________________________________________
-
- æKY 'STR#'…Resource
- æC »'STR#' Resource Control Panels
- _______________________________________________________________________________
-
- If the name for the video card that you want to display in the Options dialog
- box is different from the name in the declaration ROM of the video card, you can
- include a 'STR#' resource. This resource must contain pairs of Pascal strings.
- The first string in each pair must be identical to the name of a video card as
- returned by the Slot Manager’s SReadDrvrName function (minus the period that the
- Slot Manager prefixes to the name). The second string in each pair is the name
- that you want to display in the Options dialog box. You can have as many pairs
- of names in one 'STR#' resource as you wish; the Monitors control panel uses the
- first match it finds.
-
- _______________________________________________________________________________
-
- æKY 'gama'…Resources
- æC »'gama' Resources Control Panels
- _______________________________________________________________________________
-
- When the user presses the Option key while clicking on the Options button in the
- Monitors control panel, a list of gamma tables is displayed, as shown in Figure
- 9-2. The software driver for a video card uses a gamma table to correct for the
- fact that the intensity of each color on a video display is not linearly
- proportional to the intensity of the electron beam; in other words, the gamma
- table helps the video driver to provide the most accurate colors possible for a
- video display. Because the user might prefer a nonstandard color correction,
- many developers of video cards provide more than one gamma table for a given
- card.
-
- To include one or more gamma tables for a video card, include in the Monitors
- extension file a resource of type 'gama' for each gamma table. The user can
- select which gamma table to use with the monitor by clicking the name of that
- table, or can select the default gamma table for that monitor by clicking the
- box that appears above the gamma table (see Figure 9-2). The default gamma table
- for a monitor is the one listed in the 'scrn' resource. Gamma tables are
- discussed in the chapter on NuBus Card Driver Design in Designing Cards and
- Drivers for the Macintosh Family and in the Graphics Devices chapter of Volume
- V. The 'gama' resource type is defined in the Resource Manager chapter of this
- volume. The 'scrn' resource is described in the Graphics Devices chapter of
- Volume V.
-
- _______________________________________________________________________________
-
- æKY 'FREF',…'BNDL',…'ICN#',…and…Owner…Resources
- æC »'FREF', 'BNDL', 'ICN#', and Owner Resources Control Panels
- _______________________________________________________________________________
-
- The 'FREF', 'BNDL', 'ICN#', and owner resources work together to give your file
- a distinctive appearance on the desktop. These resource types are described in
- the Resource Manager chapter of this volume, and examples of these resources are
- given in the sample code at the end of this chapter.
-
- _______________________________________________________________________________
-
- æKY 'INIT'…Resource
- æC »'INIT' Resource Control Panels
- _______________________________________________________________________________
-
- A file that contains an extension to the Monitors control panel can contain an
- 'INIT' resource. If this file is located in the INIT folder the system executes
- the 'INIT' resource when the machine is switched on or reset. 'INIT' resources
- are discussed in the System Resource chapter of Volume IV and in the Start
- Manager chapter of Volume V. The 'INIT' resource acts independently of other
- resources in the file; it need not be related to the Monitors extension in any
- way.
-
- _______________________________________________________________________________
-
- æKY Sample…of…a…File…That…Extends…the…Monitors…Control…Panel
- æC »Sample of a File That Extends the Monitors Control Panel Control Panels
- _______________________________________________________________________________
-
- Listing 9-1 shows the components of a file that extends the Monitors Control
- Panel.
-
- Listing 9-1. Sample of a File That Extends the Monitors Control Panel
-
- Pascal source code:
-
- UNIT MonExtendCDEV;
-
- INTERFACE
-
- USES
-
- MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf;
-
- CONST
-
- textItm = 1; {first editTExt item in cdev}
-
- SlotCount = 6;
- INITMSG = 1; {sent before the dialog is actually displayed}
- OKMSG = 2; {indicates we are quitting and actions should stick}
- CANCELMSG = 3; {indicates we are quitting and actions should not stick}
- HITMSG = 4; {sent when an extensions control is hit}
- NULMSG = 5; {a periodic event}
- UPDATEMSG = 6; {this SHOULD be handled by user code and built-in controls}
- ACTIVATEMSG = 7; {currently not used as we are a modalDialog}
- DEACTIVATEMSG = 8;{currently not used as we are a modalDialog}
- KEYEVTMSG = 9; {sent for keyboard events. }
- { TextEdit should handle automatically}
- SUPERMSG = 10; {sent if should show Super User controls}
- NORMALMSG = 11; {sent if should not show Super User controls}
- STARTUPMSG = 12; {sent as soon as the code is loaded, }
- { before any resources are found}
- TYPE
- ScrnRecord = RECORD {‘scrn’ info for each screen}
- srDrvrHW: INTEGER; {spDrvrHW from slot decl mgr’s device type}
- srSlot: INTEGER; {Slot number for the screen’s video card}
- srDCtlDevBase: LONGINT; {Base address of card’s memory}
- srMode: INTEGER; {sRsrcID for desired mode}
- srFlagMask: INTEGER; {$77FE}
- srFlags: INTEGER; {active, main screen, B/W or color}
- srColorTable: INTEGER; {Resource ID of desired ‘clut’}
- srGammaTable: INTEGER; {Resource ID of desired ‘gama’}
- srRect: Rect; {Device’s rectangle, global coordinates}
- srCtlCount: INTEGER; {Number of control calls}
- END;
-
- ScrnRecordPtr = ^ScrnRecord;
- ScrnRecordHandle = ^ScrnRecordPtr;
-
- ScrnRsrc = RECORD {Complete ‘scrn’ resource}
- count: INTEGER; {Number of screens configured here}
- scrnRecs: ARRAY[1..SlotCount] OF ScrnRecord; {Config for @ one}
- END;
-
- ScrnRsrcPtr = ^ScrnRsrc;
- ScrnRsrcHandle = ^ScrnRsrcPtr;
- CodePtr = ^LONGINT; {Dummy pointer type}
-
- FUNCTION MonExtend (message, {the action to handle}
- Item, {the DITL item hit or 0}
- numItems: INTEGER; {the number of Monitors last item}
- monitorValue:LONGINT; {value returned last time. Defaults to 0}
- mDialog: DialogPtr; {the dialog pointer}
- theEvent: EventRecord;{event that caused the message to happen}
- ScreenNum: INTEGER; {the number of the screen to affect}
- VAR Screens:ScrnRsrcHandle; {the screen resource to change if desired}
- VAR ScrnChanged: BOOLEAN {TRUE if Monitors should clean up screens}
- ):LONGINT; {value to pass back as monitorValue }
- { or an error code}
-
-
- IMPLEMENTATION
-
- FUNCTION MonExtend ( message,Item,numItems: INTEGER;
- monitorValue: LONGINT;
- mDialog: DialogPtr;
- theEvent: EventRecord;
- ScreenNum: INTEGER;
- VAR Screens: ScrnRsrcHandle;
- VAR ScrnChanged: BOOLEAN
- ):LONGINT;
-
- VAR
- tempChar : CHAR;
- BEGIN
- CASE message OF
- initMSG: {initialize cdev}
- BEGIN
- {do nothing at all}
- END;
- END;
- MonExtend := monitorValue; { return old value}
- END; {MonExtend}
- END.
-
- Rez source code:
-
- #include "Types.r"
- #include "SysTypes.r"
-
- type 'kcah' as 'STR ';
-
- type 'card' as 'STR ';
-
- type 'sysz' { unsigned hex longint; };
-
- type 'RECT'
- {
- rect;
- };
-
- type 'vers' {
- hex byte; /* Major revision in BCD*/
- hex byte; /* Minor vevision in BCD*/
- hex byte development = 0x20, /* Release stage*/
- alpha = 0x40,
- beta = 0x60,
- final = 0x80, /* or */ release = 0x80;
- hex byte; /* Non-final release # */
- integer Country; /* Country code*/
- pstring; /* Short version number */
- pstring; /* Long version number */
- };
-
- resource 'sysz' (0, purgeable) {
- $1000 /* about 64k needed in system heap, for a test */
- };
-
-
- resource 'vers' (1) {
- 0x01, 0x00, release, 0x00,
- verUS,
- "0.00",
- "0.00, Copyright © 1989 Apple Computer, Inc."
- };
-
- resource 'kcah' (0, purgeable) {
- "Monitors Extension Sample by Macintosh Developer Technical Support"
- };
-
- resource 'BNDL' (128, purgeable) {
- 'kcah',
- 0,
- {
- 'ICN#', {0, 128},
- 'FREF', {0, 128}
- }
- };
-
-
- resource 'ICN#' (128, purgeable) {
- { /* array: 2 elements */
- /* [1] */
- $"0000 0000 07FF FFE0 0800 0010 09FF FF90"
- $"0A00 0050 0A00 0050 0AF3 E750 0A88 8850"
- $"0A88 8850 0A88 8650 0A88 8150 0A88 8150"
- $"0AF0 8E50 0A00 0050 0A00 0050 0A00 0050"
- $"09FF FF90 0800 0010 0FFF FFF0 0800 0010"
- $"0800 0010 0800 0010 0800 7F10 0800 0010"
- $"0800 0010 0800 0010 0800 0010 07FF FFE0"
- $"0400 0020 0400 0020 0400 0020 07FF FFE0",
- /* [2] */
- $"0000 0000 07FF FFE0 0FFF FFF0 0FFF FFF0"
- $"0FFF FFF0 0FFF FFF0 0FFF FFF0 0FFF FFF0"
- $"0FFF FFF0 0FFF FFF0 0FFF FFF0 0FFF FFF0"
- $"0FFF FFF0 0FFF FFF0 0FFF FFF0 0FFF FFF0"
- $"0FFF FFF0 0FFF FFF0 0FFF FFF0 0FFF FFF0"
- $"0FFF FFF0 0FFF FFF0 0FFF FFF0 0FFF FFF0"
- $"0FFF FFF0 0FFF FFF0 0FFF FFF0 07FF FFE0"
- $"07FF FFE0 07FF FFE0 07FF FFE0 07FF FFE0"
- }
- };
-
- data 'ICON' (-4096, purgeable) {
- $"0000 0000 07FF FFE0 0800 0010 09FF FF90"
- $"0A00 0050 0A00 0050 0AF3 E750 0A88 8850"
- $"0A88 8850 0A88 8650 0A88 8150 0A88 8150"
- $"0AF0 8E50 0A00 0050 0A00 0050 0A00 0050"
- $"09FF FF90 0800 0010 0FFF FFF0 0800 0010"
- $"0800 0010 0800 0010 0800 7F10 0800 0010"
- $"0800 0010 0800 0010 0800 0010 07FF FFE0"
- $"0400 0020 0400 0020 0400 0020 07FF FFE0"
- $"0000 0000 07FF FFE0 0FFF FFF0 0FFF FFF0"
- $"0FFF FFF0 0FFF FFF0 0FFF FFF0 0FFF FFF0"
- $"0FFF FFF0 0FFF FFF0 0FFF FFF0 0FFF FFF0"
- $"0FFF FFF0 0FFF FFF0 0FFF FFF0 0FFF FFF0"
- $"0FFF FFF0 0FFF FFF0 0FFF FFF0 0FFF FFF0"
- $"0FFF FFF0 0FFF FFF0 0FFF FFF0 0FFF FFF0"
- $"0FFF FFF0 0FFF FFF0 0FFF FFF0 07FF FFE0"
- $"07FF FFE0 07FF FFE0 07FF FFE0 07FF FFE0"
- };
-
- resource 'DITL' (-4096, purgeable) {
- { /* array DITLarray: 1 element */
- /* [1] */
- {15, 110, 50, 280},
- StaticText {
- disabled,
- "Macintosh Developer Technical Support Mo"
- "nitor Extension Example © 1989"
- }
- }
- };
-
- resource 'FREF' (128, purgeable) {
- 'cdev',
- 0,
- ""
- };
-
-
-
-
- resource 'RECT' (-4096, purgeable)
- {
- {-50,0,0,320}
- };
-
- resource 'card' (-4096, purgeable)
- {
- "Toby frame buffer card"
- };
- _______________________________________________________________________________
-
- æKY Including…Another…Control…Panel…Definition…in…a…Monitors…Extension
- æC »Including Another Control Panel Definition in a Monitors Extension Control Panels
- _______________________________________________________________________________
-
- A control panel file that contains an extension to the Monitors control panel
- can also contain a definition for another, separate control panel. You might
- want to include both an extension to the Monitors control panel and a new
- control panel definition in the same file, for example, if each controlled some
- features of the same video card. Any control panel definition must include a
- 'cdev' resource and the other resources described in the Control Panel chapter
- of Volume V.
-
- Because the control panel resources and the Monitors extension resources in the
- file have different resource ID numbers, the Finder handles them separately. If
- the user opens a control panel file containing both a control panel definition
- and an extension to the Monitors control panel, the control panel defined in
- that file appears on the screen and the Finder ignores the Monitors extension in
- that file. If the user opens the Monitors control panel file, then the Monitors
- cdev function searches the other control panel files in the same folder for
- extensions and ignores any 'cdev' resources it finds in those files. The user
- cannot open a control panel file that contains only an extension to the Monitors
- control panel; such a file can be opened only by the Monitors cdev function.
-
- _______________________________________________________________________________
-
- æKY Summary…of…the…Extension…File…for…the…Monitors…Control…Panel
- æC »SUMMARY OF THE EXTENSION FILE FOR THE MONITORS CONTROL PANEL Control Panels
- _______________________________________________________________________________
-
- The following cards summarize the constants and routines for the Monitors
- Control Panel.
- _______________________________________________________________________________
-
- æKY Control…Panels…Constants
- æC »Constants Control Panels
- _______________________________________________________________________________
-
- CONST
- INITMSG = 1; {initialization}
- OKMSG = 2; {user clicked on OK button}
- CANCELMSG = 3; {user clicked on CANCEL button}
- HITMSG = 4; {user clicked on control in Options dialog}
- NULMSG = 5; {periodic event}
- UPDATEMSG = 6; {update event}
- ACTIVATEMSG = 7; {not used}
- DEACTIVATEMSG = 8; {not used}
- KEYEVTMSG = 9; {keyboard event}
- SUPERMSG = 10; {show superuser controls}
- NORMALMSG = 11; {show only normal controls}
- STARTUPMSG = 12; {code has been loaded}
- _______________________________________________________________________________
-
- æKY Control…Panels…Routines
- æC »Routines Control Panels
- _______________________________________________________________________________
-
- FUNCTION Mntr (message, Item, numItems: Integer; monitorValue: LongInt;
- mDialog: DialogPtr; theEvent: EventRecord; ScreenNum: Integer;
- VAR Screens: ScrnRsrcHandle; VAR ScrnChanged: BOOLEAN) :
- LongInt;
-
- _______________________________________________________________________________
-
-
- æKY DatabaseAccessManager
- æC
- _______________________________________________________________________________
-
- DATABASE ACCESS MANAGER
- _______________________________________________________________________________
-
- About…the…Database…Access…Manager…Chapter
- About…the…Database…Access…Manager
- The…High-Level…Interface
- Sending…a…Query…Through…the…High-Level…Interface
- Retrieving…Data…Through…the…High-Level…Interface
- The…Low-Level…Interface
- Sending…a…Query…Through…the…Low-Level…Interface
- Retrieving…Data…Through…the…Low-Level…Interface
- Comparison…of…the…High-Level…and…Low-Level…Interfaces
- Database…Access…Manager…User…Interface…Guidelines
- General…Guidelines…for…Database…Access…Manager
- User…Control
- User…Feedback
- High-Level…Database…Access
- Low-Level…Database…Access
- Query…Documents
- Using…the…Database…Access…Manager
- Executing…Routines…Asynchronously
- Using…the…High-Level…Interface
- Writing…a…Status…Routine…for…High-Level…Functions
- Using…the…Low-Level…Interface
- Getting…Information…About…Sessions…in…Progress
- Processing…Query…Results
- Getting…Query…Results
- Converting…Query…Results…to…Text
- Creating…a…Query…Document
- Contents…of…a…Query…Document
- Query…Records…and…Query…Resources
- Query…Records
- Query…Resources
- Writing…a…Query…Definition…Function
- Database…Access…Manager…Routines
- Asynchronous…Execution…of…Routines
- Initializing…and…Closing…the…Database…Access…Manager
- High-Level…Interface
- Handling…Query…Documents
- Handling…Query…Results
- Low-Level…Interface
- Controlling…the…Session
- Sending…and…Executing…Queries
- Retrieving…Results
- Installing…and…Removing…Result…Handlers
- Summary…of…the…Database…Access…Manager
- Database…Access…Manager…Constants
- Database…Access…Manager…Data…Types
- Database…Access…Manager…Routines…Summary
- Database…Access…Manager…Result…Codes
- Assembly-Language…Information…for…Database…Access…Manager
- _______________________________________________________________________________
-
-
-
- æKY About…the…Database…Access…Manager…Chapter
- æC »ABOUT THIS CHAPTER Database Access Manager
- _______________________________________________________________________________
-
- This chapter describes how your application can use the Database Access Manager
- to communicate with a database application that is running on a remote computer.
- It also provides information for system programmers who want to provide an
- interface between the Database Access Manager and a remote database server, and
- for those who want to provide templates to be used by applications for database
- transactions.
-
- The Database Access Manager is available with system software version 7.0. Use
- the Gestalt function described in the Compatibility Guidelines chapter of this
- volume to determine whether the Database Access Manager is present.
-
- The Database Access Manager allows your application to communicate with a
- database even if you do not know anything about databases in general or the
- specific database program that the users of your software will be using. All
- your application needs is a few high-level Database Access Manager functions and
- access to a file called a query document. The query document, provided by
- another application, contains commands and data (the query) in the format
- appropriate for the database program on the remote computer.
- The Database Access Manager also provides a low-level interface for use by
- applications that are capable of creating their own queries and that therefore
- do not have to use query documents.
- If your application uses only the high-level interface and relies on query
- documents created by other programs, then all the routines you need to know are
- described in this chapter. However, if you want to create a query document or an
- application that uses the low-level interface, then you must also be familiar
- with the command language used by the remote database server.
- You need the information in this chapter if you want your application to
- communicate with a remote database application, if you want to write a query
- document, or if you want to write a database extension, that is, code that
- provides an interface between the Database Access Manager and a remote database
- program. To create a database extension, you must also know how to communicate
- with the remote database server.
-
- Note: Although the Database Access Manager was designed to make it easy for
- your application to communicate with a database running on a remote computer,
- there is no reason in principle why the database could not be local—that is,
- running on the same computer as your application. To implement such a system,
- you would have to have a database that runs on a Macintosh computer and that has
- a command-language interface, plus a database extension that can use that
- command language. In most cases, it would be much simpler to run the database as
- a separate application and use the Clipboard to transfer data into and out of
- the database.
-
- Apple Computer, Inc. provides a database extension that uses the CL/1™
- connectivity language. If you want to write an application that uses the
- low-level interface to communicate with a CL/1 server, or if you want to create
- a query document that uses CL/1, you must be familiar with CL/1. CL/1
- Connectivity Language, available from APDA, fully describes this language.
-
- The rest of this chapter provides an overview and description of the Database
- Access Manager, including
-
- • diagrams and conceptual descriptions of the components and processes
- involved in using the high-level and low-level interfaces
-
- • descriptions, flowcharts, and program fragments that provide a
- step-by-step guide to the use of the high-level and low-level interfaces
-
- • instructions for creating a query document
-
- • complete descriptions of all Database Access Manager routines
- _______________________________________________________________________________
-
- æKY About…the…Database…Access…Manager
- æC »ABOUT THE DATABASE ACCESS MANAGER Database Access Manager
- _______________________________________________________________________________
-
- The Database Access Manager provides a standard interface that enables Macintosh
- applications to communicate with any number of databases through a variety of
- database servers. A database server is the application on the remote computer
- that acts as an interface between the database management software on the
- Macintosh® computer and the database software on the remote computer.
- The Database Access Manager has two application interfaces: the high-level
- interface and the low-level interface. If the proper database extension and
- query documents are available in the user’s system, you can use the high-level
- interface to communicate with a database without having any knowledge of the
- command language that the database server uses. Even if you use the low-level
- interface, your application can isolate the user from any specific knowledge of
- the database or the database server’s command language.
-
- This section presents an overview and description of the Database Access
- Manager, including diagrams and conceptual descriptions of the components and
- processes involved in using the high-level and low-level interfaces. Next,
- “Using the Database Access Manager” includes descriptions, flow charts, and
- program fragments that provide a step-by-step guide to the use of the high-level
- and low-level interfaces. The section “Creating a Query Document” describes the
- contents and function of a query document. You do not have to read this section
- unless you are writing an application that creates query documents, although if
- you are using the high-level interface you might be interested to know just how
- a query document works.
- Figure 7-1 illustrates database communication. The arrows in Figure 7-1 show the
- flow of information, not the paths of commands or control signals. See Figures
- 7-2 and 7-3 for the sequences involved in sending and retrieving data.
-
- ø 7.1 The database communication system
-
- _______________________________________________________________________________
-
- æKY The…High-Level…Interface
- æC »The High-Level Interface Database Access Manager
- _______________________________________________________________________________
-
- As Figure 7-1 shows, a database-naive application—that is, one that cannot
- prepare a query for a specific database server—uses the Database Access
- Manager’s high-level routines to communicate with a remote database server.
- Because the application cannot prepare a query, it must use a query document to
- provide one. A query document can contain code, called a query definition
- function, that prompts the user for information and modifies the query before
- the Database Access Manager sends it to the remote database server. The exact
- format of a query definition function is described in the section “Writing a
- Query Definition Function” later in this chapter.
-
- Note: The term query refers to any string of commands that can be executed by a
- database server. A query can send data to a database, retrieve data from a
- database, or reorganize the data in a database. The Database Access Manager does
- not interpret or execute the query; it only implements the interface (sometimes
- called the application program interface, or API) that allows you to send the
- query to the database server.
- When you want to use the high-level routines to execute a query on a remote
- database server, you first select a query document or allow the user to select
- one. You use high-level routines to
-
- • open the query document
-
- • execute the query definition function to modify the query
-
- • send the query to the remote database server
-
- • retrieve the results from any query that asks for information from the
- database.
-
- • convert to text the results returned by a query
-
- For example, suppose Mom’s Rubber Duck Company has a database on a minicomputer
- that contains a mailing list of all of its customers. The database has a CL/1
- interface and Mom’s marketing manager has a Macintosh computer with an
- application that uses high-level Database Access Manager routines to communicate
- with the remote database server. As Figure 7-2 illustrates, the marketing
- manager must also have a query document, created by another application, that
- she can use to send a new address to the mailing list on the remote
- minicomputer. The query document can be as complex or as simple as its creator
- cares to make it; in this example, the query document is designed specifically
- to change addresses in the rubber duck mailing list. The marketing manager might
- have several other query documents available as well; one to add new entries to
- the mailing list, one to extract a mailing list for a specific zip code, one to
- list all of the customers who have made a purchase within the last year, and so
- on.
-
- ø 7.2 Using high-level Database Access Manager routines to send a query to a
- database and retrieve data
- _______________________________________________________________________________
-
- æKY Sending…a…Query…Through…the…High-Level…Interface
- æC »Sending a Query Through the High-Level Interface Database Access Manager
- _______________________________________________________________________________
-
- To update the mailing list with a new address for customer Marvin Moody, the
- marketing manager chooses the Open Query menu item from the File menu in her
- application. From the list of query documents displayed, she chooses one named
- New Address.
-
- The application calls the Database Access Manager function DBGetNewQuery. This
- function opens the New Address query document and creates a partial query from
- the information in the query document. The partial query specifies the type of
- data (a character string), the column into which the data item should go (the
- address column), and the row to be modified (the Marvin Moody row). The partial
- query lacks the actual data (the new address) that the marketing manager wants
- to send to the database.
-
- Next, the application calls the DBStartQuery function, which in turn calls the
- query definition function in the query document. The query definition function
- displays a dialog box that asks for the name of the person and the new address.
- When the marketing manager types in the requested information and clicks OK, the
- query definition function adds the data to the partial query in memory. The
- query is now complete.
-
- Next, the DBStartQuery function sends the query to the CL/1 database extension,
- and the database extension sends the query over a communications net to the
- remote CL/1 server. Finally, the DBStartQuery function commands the CL/1 server
- to execute the query.
- _______________________________________________________________________________
-
- æKY Retrieving…Data…Through…the…High-Level…Interface
- æC »Retrieving Data Through the High-Level Interface Database Access Manager
- _______________________________________________________________________________
-
- When an application wants to retrieve data that it requested from a database,
- the application calls the DBGetQueryResults function. This function determines
- when the data is available, retrieves it from the database server, and places
- the data in a record in memory. The application can then call the
- DBResultsToText function, which uses routines called result handlers to convert
- each data item to a character string. The DBResultsToText function passes to the
- application a handle to the converted data. Data items and result handlers are
- described in “Processing Query Results” later in this chapter.
-
- _______________________________________________________________________________
-
- æKY The…Low-Level…Interface
- æC »The Low-Level Interface Database Access Manager
- _______________________________________________________________________________
-
- A database-aware application communicates through the low-level interface of the
- Database Access Manager. You can use the low-level interface to
-
- • establish communication with the remote database server, sending the user
- name, password, and other information to the database server
-
- • send a query to the database server
-
- • execute the query that you have sent to the database server
-
- • halt execution of the query
-
- • return status and errors from the remote database server
-
- • send data to the database
-
- • retrieve data from the database
-
- For example, suppose Mom’s Rubber Duck Company has a database on a minicomputer
- that contains a mailing list of all of its customers. The database has a CL/1
- interface and Mom’s marketing manager has a Macintosh computer with an
- application that uses low-level Database Access Manager routines to communicate
- with the remote database server. Figure 7-3 illustrates the use of the low-level
- interface. Notice that if you use the high-level interface (Figure 7-2), the
- query document and the Database Access Manager prepare the query, send the
- query, retrieve the query results, and translate the data for you. If you use
- the low-level interface, on the other hand, you must perform these functions
- yourself.
-
- ø 7.3 Using low-level Database Access Manager routines to send a query to a
- database and retrieve data
- _______________________________________________________________________________
-
- æKY Sending…a…Query…Through…the…Low-Level…Interface
- æC »Sending a Query Through the Low-Level Interface Database Access Manager
- _______________________________________________________________________________
-
- To update the mailing list with a new address for customer Marvin Moody, the
- marketing manager enters the new address into her application. The application
- prepares a CL/1 statement (a query) that specifies the type of data (a character
- string), the column into which the data item should go (the address column), the
- row to be modified (the Marvin Moody row), plus the actual data the application
- wishes to send (Marvin Moody’s address). The application then passes this query
- to the Database Access Manager using the low-level interface. (The application
- can send the query in several pieces, or all at once). The Database Access
- Manager sends the query to the CL/1 database extension in the Macintosh, and the
- database extension sends the query to the remote CL/1 server.
- _______________________________________________________________________________
-
- æKY Retrieving…Data…Through…the…Low-Level…Interface
- æC »Retrieving Data Through the Low-Level Interface Database Access Manager
- _______________________________________________________________________________
-
- Once the query begins executing, the application can periodically check with the
- remote database server to determine whether the data is ready (Figure 7-3). When
- the data is available, the application must retrieve it one data item at a time.
- An application that uses the low-level interface must determine the data type of
- each data item, convert the data into a format that is meaningful to the user,
- and store the data in memory allocated by the application. Data types are
- described in “Processing Query Results” later in this chapter.
-
- Note that neither the Database Access Manager nor the database extension reads,
- modifies, or acts on the query that an application sends to the remote database
- server. The database server does execute the query, causing the database to
- accept new data or prepare data for the application. To use the low-level
- interface to communicate with a remote database server, your application must be
- capable of preparing a query that can be executed by the database server.
-
- _______________________________________________________________________________
-
- æKY Comparison…of…the…High-Level…and…Low-Level…Interfaces
- æC »Comparison of the High-Level and Low-Level Interfaces Database Access Manager
- _______________________________________________________________________________
-
- An application that uses the low-level interface to send a query to the database
- server must prepare the query, initiate communication with the database server,
- send the query to the database server, and execute the query. Each step in this
- process requires calling one or more low-level routines.
-
- The low-level application interface uses functions that are very similar to the
- CL/1 application program interface (API) routines. In addition, there is a
- one-to-one correspondence between the low-level routines and the commands sent
- by the Database Access Manager to the database extension. In the case of the
- CL/1 database extension, there is also a close relationship between these
- routines and the commands sent by the database extension to the remote CL/1
- server.
-
- The high-level interface between the Database Access Manager and the
- application, on the other hand, consists of only a few routines, each of which
- might call several low-level routines to accomplish its tasks. For example, a
- single high-level function can call the query definition function, initiate
- communication with the remote database server, send the query to the remote
- database server, and execute the query.
-
- Although in concept the low-level routines and high-level routines serve
- separate purposes, there is nothing to prevent you from using calls to both in a
- single application. For example, you might use low-level routines to send a
- query to a remote database server and high-level routines to read the results
- and convert them to text.
-
- _______________________________________________________________________________
-
- æKY Database…Access…Manager…User…Interface…Guidelines
- æC »DATABASE ACCESS MANAGER USER INTERFACE GUIDELINES Database Access Manager
- _______________________________________________________________________________
-
- System software version 7.0 provides the ability for applications to access
- information from a wide variety of databases on remote minicomputers or
- mainframe computers. This section presents interface guidelines regarding
- database access. Applications can implement the Database Access Manager in three
- ways. An application can
-
- • directly use the Toolbox routines to establish and manage a connection
- with a target database (low-level access)
-
- • create a query document that other applications can use to communicate
- with a target database (low-level access)
-
- • execute a query document that gains database access for the application
- (high-level access)
- _______________________________________________________________________________
-
- æKY General…Guidelines…for…Database…Access…Manager
- æC »General Guidelines Database Access Manager
- _______________________________________________________________________________
-
- When you develop an application that uses the Database Access Manager, you
- should consider these user interface guidelines and the associated principles.
- _______________________________________________________________________________
-
- æKY User…Control
- æC »User Control Database Access Manager
- _______________________________________________________________________________
-
- When designing a database access feature or application, keep in mind that the
- user should have access to the computer’s abilities as much as possible. Design
- your application so that as much as possible of the database access process
- happens in the background. Call the Database Access Manager asynchronously
- whenever the database extension you are using supports asynchronous calls. In
- particular data retrieval queries should run in the background.
-
- After issuing a query, return control of the computer to users so that they may
- work on other tasks or switch to other applications while the query runs. Any
- time a background task requires the user’s attention, follow the guidelines in
- the User Interface Guidelines chapter to notify the user. A background task
- should never take control from the user by posting an alert box in front of the
- active application’s windows. Any message that you post should identify the
- query that requires attention. For example a dialog box may display the message,
- “The query Get Employee Information was cancelled because the connection was
- unexpectedly broken.”
-
- If your application allows more than one simultaneous connections to databases,
- or more than one query document to run, provide a modeless window that lists the
- open connections and queries. This way the user can monitor the status of open
- queries and cancel them if necessary.
-
- Allow the user to limit the amount of disk space that must remain free after any
- transaction. For example, a user may wish to specify that 1 MB of space always
- be free. Cancel any transaction that would exceed the user’s limit and notify
- the user.
- _______________________________________________________________________________
-
- æKY User…Feedback
- æC »User Feedback Database Access Manager
- _______________________________________________________________________________
-
- Keep the user informed about status, progress, and error conditions. Inform the
- user before the computer becomes modal and unavailable. Use the spinning beach
- ball cursor or the animated watch cursor to indicate a call that takes several
- seconds to execute. Use a dialog box to indicate any process that lasts longer
- than a few seconds. For example, connecting to a remote database could take a
- couple of minutes. In this case include a Cancel button in the dialog box so
- that the user can cancel the operation. When possible display a progress
- indicator to show how long a process lasts. Warn the user before doing anything
- potentially dangerous or irreversible, such as deleting all of a user’s data
- files to replace them with data retrieved from a database. Allow the user to
- cancel an interaction whenever possible.
-
- When a data retrieval query terminates prematurely, retrieve the data and make
- it available to the user with a warning that it is incomplete. This allows the
- user to take advantage of the partial data and decide whether or not to run the
- query again.
- _______________________________________________________________________________
-
- æKY High-Level…Database…Access
- æC »High-Level Database Access Database Access Manager
- _______________________________________________________________________________
-
- High-level database access can be implemented by applications that want to
- communicate with a remote database. In this case your application calls a query
- document to do the work of communicating with the database. Applications that
- implement this type of database access need to follow the general guidelines
- presented previously in this section, and the guidelines described here.
- Include an Open Query menu command in the File menu. The command is equivalent
- to the Open file command in meaning. When the user chooses this command, display
- the standard file dialog box filtered to show only available query documents.
- The user then can choose the desired query document. The query document sends
- the query to the database. Depending on the type of query, the database could
- receive information, send back information, report the status of the database,
- or perform some other task. Upon terminating the data access session, save any
- data retrieved into the query document.and then close the query document.
- Users can subscribe to the data in a query document using the Edition Manager by
- subscribing to the query document. See the Edition Manager chapter for more
- information.
- _______________________________________________________________________________
-
- æKY Low-Level…Database…Access
- æC »Low-Level Database Access Database Access Manager
- _______________________________________________________________________________
-
- If you implement low-level database access, you are responsible for developing
- and implementing the corresponding user interface. In addition to the general
- guidelines presented previously, follow the guidelines described here when you
- design low-level database access features.
-
- When the target database is ready to return data, you can retrieve it all and
- then display it to the user. Or you could display the data as it arrives. If the
- data arrives slowly, it’s best to display it one record at a time as it arrives.
- This way the user can preview the data and decide if it’s the desired
- information.
-
- Provide some method of progress monitoring for the user. The Database Access
- Manager allows many connections to target databases to be open at one time. A
- user may want to see some indication of how many open connections exist, their
- status, and their progress. This is an appropriate place to provide a way for
- the user to cancel a query in progress.
- _______________________________________________________________________________
-
- æKY Query…Documents
- æC »Query Documents Database Access Manager
- _______________________________________________________________________________
-
- To implement high-level database access, your application executes a query
- document that can use a database extension to connect to a remote database and
- access and transfer information. This section describes guidelines specific to
- query documents. Also consider the general guidelines presented previously.
- All query documents should behave in fundamentally the same way. They should be
- self-explanatory and should never run automatically. When your application opens
- a query document, it should display a dialog box with enough information about
- the query so that the user can decide if it’s the right query. The dialog box
- should describe the purpose of the query, what kind of data it transfers and
- which direction, the type of database it accesses, and any warnings or
- instructions. The dialog box can describe how the user interprets the data, such
- as the name of each field in a record. Figure 7-4 shows an example of a query
- document dialog box.
-
- ø 7.4 Query document identification dialog box
-
- This dialog box should allow the user to cancel the request for data. In
- addition, it may be useful to allow the user to set parameters in text boxes,
- check boxes, or radio buttons. For example, a query to a database of financial
- information could provide a list of these options: a trial balance,
- profit-and-loss statements, or net worth reports. Save the last set of
- user-specified parameters with the query document. This way the user can review
- the parameters used to generate the data.
-
- Once a query starts running, it must be able to complete its task without user
- intervention. If a query must run modally (that is, it must run to completion
- before returning control to the user) be sure to notify the user of its progress
- and return control to the user as soon as possible. The philosophy of this
- process is similar to that of receiving electronic mail. That is, inform the
- user when the information arrives, but let the user decide when to read it.
- Query documents should check data before it is transmitted to a database to be
- sure it’s compatible. Establish a connection with a database only after the data
- is checked.
- _______________________________________________________________________________
-
- æKY Using…the…Database…Access…Manager
- æC »USING THE DATABASE ACCESS MANAGER Database Access Manager
- _______________________________________________________________________________
-
- There are at least three different ways in which you can use the Database Access
- Manager to communicate with a database:
-
- • You can use low-level interface routines to send queries and retrieve
- data from the database. In this case, your application must be capable of
- preparing a query in a language appropriate for the remote database
- server.
-
- • You can use high-level interface routines to send queries and retrieve
- data from the database. In this case, you must have one or more query
- documents provided by another application.
-
- • You can create your own query documents and use high-level interface
- routines to send queries and retrieve data from the database. In this
- case, your application must be capable of preparing a query, but it can
- use the same query repeatedly once it has been prepared.
-
- This section describes how to use the high-level and low-level interfaces to the
- Database Access Manager to send queries to a remote database server. This
- section also describes how to call Database Access Manager functions
- asynchronously; how to determine the status of the high-level functions at
- various points in their execution (and cancel execution if you so desire); how
- to obtain information about Database Access Manager sessions that are in
- progress; and how to retrieve query results and convert them to text.
- _______________________________________________________________________________
-
- æKY Executing…Routines…Asynchronously
- æC »Executing Routines Asynchronously Database Access Manager
- _______________________________________________________________________________
-
- All of the Database Access Manager low-level routines and some of the high-level
- routines can execute asynchronously; that is, the routine returns control to the
- application before the routine has completed execution. Your application must
- call the WaitNextEvent routine periodically to allow an asynchronous routine to
- complete execution.
-
- All Database Access Manager routines that can execute asynchronously take as a
- parameter a pointer to a parameter block known as the asynchronous parameter
- block. If this pointer is NIL, the function is executed synchronously; that is,
- the routine does not return control to your application until execution is
- complete.
-
- The database extension is responsible for implementing asynchronous execution of
- Database Access Manager routines. For example, if you call the DBSend function
- to send a query to a remote database server, and the database extension calls a
- device driver, the database extension can return control to your application as
- soon as the device driver has placed its routine in the driver I/O queue. If the
- database extension you are using does not support asynchronous execution of
- routines, it returns a result code of rcDBAsyncNotSupp and terminates execution
- of the routine.
-
- _______________________________________________________________________________
-
- æKY Using…the…High-Level…Interface
- æC »Using the High-Level Interface Database Access Manager
- _______________________________________________________________________________
-
- You can use the high-level interface to open a query document, execute the query
- definition function in the query document, establish communication (initiate a
- session) with a remote database server, send the query to the database server,
- execute the query, retrieve any data requested by the query, and convert the
- retrieved data to text. Although two or three high-level routines accomplish
- most of these tasks, you must call a few low-level routines as well to control a
- session with a database server.
-
- Figure 7-5 is a flowchart of a typical session using the high-level interface.
-
- ø 7.5 Flowchart of session using high-level interface
-
- As Figure 7-5 illustrates, you must follow this procedure to use the high-level
- interface:
-
- 1. Call the InitDBPack function to initialize the Database Access Manager.
-
- 2. Call the DBInit function to establish communication with the remote database
- server. The DBInit function returns an identification number, called a session
- ID. This session ID is unique; no other current session, for any database
- extension, has the same session ID. You must specify the session ID any time you
- want to send data to or retrieve data from this session.
-
- The DBInit function requires as input parameters the name of the database
- extension, character strings for the remote system, user name, password, and
- connection string. All of these parameters depend on the user and the user’s
- computer system, including the specific database extension, host computer,
- database server, and database management software in use. You will not know the
- user name and password when you are writing an application, and you might not
- know the values of any of these parameters. Therefore, you must display a dialog
- box that prompts the user for the necessary information.
-
- If you want the Database Access Manager to call the DBInit function for you, you
- can skip this step. The DBStartQuery function (step 5) automatically calls the
- DBInit function if a session with the database server has not already been
- established.
-
- Depending on the database extension you are using, the DBInit function might
- return a session ID of 0 if it fails to initiate a session, or it might return a
- nonzero session ID and some result code other than noErr. In the latter case,
- you can pass the session ID to the DBGetErr function to determine the cause of
- the error. If the DBInit function returns a nonzero session ID and a result code
- other than noErr, you must call the DBEnd function before making another attempt
- to open the session or closing the Database Access Manager.
-
- 3. Select the query document that you want to use and determine the resource ID
- of the 'qrsc' resource in that query document. You can use any method you like
- to select the query document. One possibility is to use the SFGetFile procedure
- to let the user select the query document. You can then use Resource Manager
- routines to determine the resource IDs of all of the 'qrsc' resources in the
- document that the user selected. The SFGetFile procedure is described in the
- Standard File chapter of Volume I and the Resource Manager is described in
- Volume I, Chapter 5.
-
- 4. Call the DBGetNewQuery function. The DBGetNewQuery function creates in
- memory a data structure called a query record from the 'qrsc' resource that you
- specify.
-
- 5. Call the DBStartQuery function specifying the handle to the query record
- that you created with the DBGetNewQuery function (step 4).
-
- You should also provide the DBStartQuery function with a handle to your status
- routine. A status routine is a routine that you provide that can update windows,
- check the results of the low-level calls made by the DBStartQuery and
- DBGetQueryResults functions, and cancel execution of these functions when you
- consider it appropriate to do so.
-
- The DBStartQuery function calls the query definition function referred to by the
- query record (if any). The query definition function can prompt the user for
- information and modify the query record.
-
- After the query definition function has completed execution, the DBStartQuery
- function calls your status routine so that you can update your windows if
- necessary. The DBStartQuery function then checks to see if communications have
- been established with the remote database server. If not, it calls your status
- routine so that you can put up a status dialog box, and then calls the DBInit
- function. The DBStartQuery function obtains the values it needs for the DBInit
- function parameters from the query record. When the DBInit function completes
- execution, the DBStartQuery function calls your status routine again.
-
- Once communications have been established, the DBStartQuery function calls the
- DBSend function to send the query specified by the query record to the remote
- database server, and, when the DBSend function has completed execution, calls
- your status routine. Finally, the DBStartQuery function uses the DBExec function
- to execute the query. The DBStartQuery function calls your status routine after
- the DBExec function has completed execution (that is, the query has started
- executing and the DBExec function has returned control to the DBStartQuery
- function) and again just before the DBStartQuery function completes execution.
-
- 6. Use the DBState function to determine the status of the query.
-
- The DBState function tells you when the database server has finished executing
- the query you just sent. If you have requested data, the database server stores
- the data you requested but does not send it to your application until you
- request it explicitly. The DBState function tells you when the data is
- available.
-
- If you did not request data, skip to step 9.
-
- 7. Call the DBGetQueryResults function. This function calls the DBGetItem
- function repeatedly until the remote database server has returned all of the
- data available.
-
- The DBGetQueryResults function puts the returned data into a record that
- contains handles to arrays that contain the data, the type of data in each
- column, and the length of each data item.
-
- The DBGetQueryResults function calls your status routine after it retrieves each
- data item. You can use this opportunity to display the data item for the user
- and to give the user the opportunity to cancel execution of the function. The
- DBGetQueryResults function also calls your status routine just before completing
- execution, so that you can dispose of any memory allocated by the status
- routine, remove any dialog box that you displayed, and update your windows if
- necessary.
-
- To convert the returned data to text, go on to the next step. If you do not want
- to convert the returned data to text, skip to step 9.
-
- 8. Call the DBResultsToText function. This function calls a result handler
- function for each data type. The result handler converts the data to text,
- places it in a buffer, and returns a handle to the buffer. Some result handlers
- are provided with the Database Access Manager; you can provide as many with your
- application as you wish. Result handlers are discussed in “Processing Query
- Results” later in this chapter.
-
- 9. If you are finished using the query record, call the DBDisposeQuery function
- to dispose of the query record and free all the memory associated with the query
- record. If you want to reuse the same query, return to step 5. You should close
- the query document when you are finished using it. Be sure to save any changes
- to the query or query record and any data returned by the query in the query
- document.
-
- If you want to use a new query document, return to step 3. If you are finished
- using the database, go on to step 10.
-
- 10. When you are finished using the database, you must use the DBEnd function
- to terminate the session. You must call the DBEnd function after the DBInit
- function has returned a nonzero session ID, even if it also returned an error.
-
- 11. When you are finished using the Database Access Manager, call the
- QuitDBPack function to close the manager.
-
- Listing 7-1 uses the high-level interface to open a query document and execute
- the query definition function in the document. It then retrieves the data
- returned by the database server and converts the data to text.
-
- Listing 7-1. Use of the high-level interface (TO BE PROVIDED)
-
- _______________________________________________________________________________
-
- æKY Writing…a…Status…Routine…for…High-Level…Functions
- æC »Writing a Status Routine for High-Level Functions Database Access Manager
- _______________________________________________________________________________
-
- Both of the two main high-level functions, DBStartQuery and DBGetQueryResults,
- call low-level functions repeatedly. After each time they call a low-level
- function, these high-level functions call a routine that you provide, called a
- status routine. Your status routine can check the result code returned by the
- low-level function, and can cancel execution of the high-level function before
- it calls the next low-level function. Your status routine can also update your
- application’s windows after the DBStartQuery function has displayed a dialog
- box.
-
- You provide a pointer to your status routine in the statusProc parameter to the
- DBStartQuery and DBGetQueryResults functions.
-
- Here is a function declaration for a status routine.
-
- FUNCTION MyStatusFunc (message: Integer; result: OSErr; dataLen, dataPlaces,
- dataFlags: Integer; dataType: DBType; dataPtr: Ptr) :
- Boolean;
-
- Your status routine should return a value of TRUE if you want the DBStartQuery
- or DBGetQueryResults function to continue execution, or FALSE to cancel
- execution of the function. In the latter case, the high-level function returns
- the userCanceledErr result code.
-
- Note: If you call the DBStartQuery or DBGetQueryResults functions
- asynchronously, you cannot depend on the A5 register containing a pointer to
- your application’s global variables when the Database Access Manager calls your
- status routine.
-
- The message parameter tells your status routine the current status of the
- high-level function that called it. The possible values for the message
- parameter depend on which function called your routine. The following status
- messages can be sent to your status routine by the DBStartQuery function:
-
- DBStartQuery
- message Description
- kDBUpdateWind The DBStartQuery function has just called a query definition
- function. Your status routine should process any update events that your
- application has received for its windows.
-
- kDBAboutToInit The DBStartQuery function is about to call the DBInit function
- to initiate a session with a remote database server. Because initiating the
- session might involve establishing communication over a network, and because in
- some circumstances the execution of a query can tie up the user’s computer for
- some length of time, you might want to display a dialog box giving the user the
- option of canceling execution at this time.
-
- kDBInitComplete The DBInit function has completed execution. When the
- DBStartQuery function calls your status routine with this message, the result
- parameter contains the result code returned by the DBInit function. If the
- DBInit function returns the noErr result code, the DBStartQuery function calls
- the DBSend function next. If the DBInit function returns any other result code,
- you can display a dialog box informing the user of the problem before returning
- control to the DBStartQuery function. The DBStartQuery function then returns an
- error code and completes execution.
-
- kDBSendComplete The DBSend function has completed execution. When the
- DBStartQuery function calls your status routine with this message, the result
- parameter contains the result code returned by the DBSend function. If the
- DBSend function returns the noErr result code, the DBStartQuery function calls
- the DBExec function next. If the DBSend function returns any other result code
- you can display a dialog box informing the user of the problem before returning
- control to the DBStartQuery function. The DBStartQuery function then returns an
- error code and completes execution.
-
- kDBExecComplete The DBExec function has completed execution. When the
- DBStartQuery function calls your status routine with this message, the result
- parameter contains the result code returned by the DBExec function. If the
- DBExec function returns the noErr result code, the DBStartQuery function returns
- control to your application next. If the DBExec function returns any other
- result code you can display a dialog box informing the user of the problem
- before returning control to the DBStartQuery function. The DBStartQuery function
- then returns an error code and completes execution.
-
- kDBStartQueryComplete The DBStartQuery function has completed execution and is
- about to return control to your application. The function result is in the
- result parameter passed to your status routine. Your status routine can use this
- opportunity to peform any final tasks, such as disposing of memory that it
- allocated or removing from the screen any dialog box that it displayed.
-
- The following status messages can be sent to your status routine by the
- DBGetQueryResults function:
-
- DBGetQueryResults
- message Description
- kDBGetItemComplete The DBGetItem function has completed execution. When the
- DBGetQueryResults function calls your status routine with this message, the
- result parameter contains the result code returned by the DBGetItem function,
- the dataLen, dataPlaces, and dataType parameters contain the length, decimal
- places, and type of the data item retrieved, the dataFlags parameter has the
- value kDBLastColFlag (that is, the least significant bit is set to 1) if the
- data item is in the last column of the row, and the dataPtr parameter contains a
- pointer to the data item. You can use this information, for example, to check
- the data to see if it meets some criteria of interest to the user, or to display
- each data item as the DBGetItem function receives it.
-
- The DBGetQueryResults function returns a results record, which contains a handle
- to the retrieved data. The address in the dataPtr parameter points inside the
- array specified by this handle. Because the dataPtr parameter is not a pointer
- to a block of memory allocated by the Memory Manager, but just a pointer to a
- location inside such a block, you cannot use this pointer in any Memory Manager
- routines (such as GetPtrSize). Note also that you cannot rely on this pointer
- remaining valid after you return control to the DBGetQueryResults function.
-
- For each data item that it retrieves, the DBGetQueryResults function calls the
- DBGetItem function twice: once to obtain information about the next data item
- and once to retrieve the data item. The DBGetQueryResults function calls your
- status routine only after calling the DBGetItem function to retrieve a data
- item.
-
- If your status routine returns a function result of FALSE in response to the
- kDBGetItemComplete message, the results record returned by the DBGetQueryResults
- function to your application contains data through the last full row retrieved.
-
- Data types and results records are described in “Getting Query Results” later in
- this chapter.
-
- kDBGetQueryResultsComplete
-
- The DBGetQueryResults function has completed execution and is about to return
- control to your application. The function result is in the result parameter
- passed to your status routine. Your status routine can use this opportunity to
- peform any final tasks, such as disposing of memory that it allocated or
- removing from the screen any dialog box that it displayed.
-
- The values of the result, dataLen, dataPlaces, dataFlags, dataType, and dataPtr
- parameters passed to your status routine depend on the value of the message
- parameter, as mentioned in the discussions of the messages and as summarized in
- Table 7-1.
-
- Table 7-1. Values of parameters passed to a status routine
-
- Message result dataLen dataPlaces dataFlags dataPtr
- dataType
-
- kDBUpdateWind NIL NIL NIL NIL
- kDBAboutToInit NIL NIL NIL NIL
- kDBInitComplete DBInit result NIL NIL NIL
- kDBSendComplete DBSend result NIL NIL NIL
- kDBExecComplete DBExec result NIL NIL NIL
- kDBGetItemComplete DBGetItem result item info item type pointer to item
- kDBGetQueryResultsComplete
- DBGetQueryResults result
- NIL NIL NIL
-
-
- Listing 7-2 shows a status routine. This routine updates the application’s
- windows in response to the kDBUpdateWind message, displays a dialog box giving
- the user the option of canceling before the database access is initiated, and
- checks the results of calls to the DBInit, DBSend, DBExec, and DBGetItem
- functions. If one of these functions returns an error, the status routine
- displays a dialog box describing the error.
-
- Listing 7-2. A sample status routine (TO BE PROVIDED)
-
- _______________________________________________________________________________
-
- æKY Using…the…Low-Level…Interface
- æC »Using the Low-Level Interface Database Access Manager
- _______________________________________________________________________________
-
- You can use the low-level interface to establish communication (initiate a
- session) with a remote database server, send a query to the database server,
- execute the query, and retrieve any data requested by the query. You must call
- one or more low-level routines to accomplish each of these tasks.
- Figure 7-6 is a flowchart of a typical session using the low-level interface.
-
- ø 7.6 Flowchart of session using low-level interface
-
- As Figure 7-6 illustrates, you must follow this procedure to use the low-level
- interface:
-
- 1. Call the InitDBPack function to initialize the Database Access Manager.
-
- 2. Call the DBInit function to establish communication with the remote database
- server. The DBInit function returns an identification number, called a session
- ID. This session ID is unique; no other current session, for any database
- extension, has the same session ID. You must specify the session ID any time you
- want to send data to or retrieve data from this session.
-
- The DBInit function requires as input parameters the name of the database
- extension and character strings for the remote system, user name, password, and
- connection string. All of these parameters depend on the user and the user’s
- computer system, including the specific database extension, remote computer,
- database server, and database management software in use. You will not know the
- user name and password when you are writing an application, and you might not
- know the values of any of these parameters. Therefore, you must display a dialog
- box that prompts the user for the necessary information.
-
- Depending on the database extension you are using, the DBInit function might
- return a session ID of 0 if it fails to initiate a session, or it might return a
- nonzero session ID and a result code other than noErr. In the latter case, you
- can pass the session ID to the DBGetErr function to determine the cause of the
- error. If the DBInit function returns a nonzero session ID and a result code
- other than noErr, you must call the DBEnd function before making another attempt
- to open the session or closing the Database Access Manager.
-
- 3. Prepare a query, and send it to the database server by calling the DBSend
- and DBSendItem functions one or more times.
-
- An application that uses the low-level interface must be capable of creating a
- query for the database server in the language and format required by that
- database server.
-
- The DBSend function sends a query or a portion of a query to the remote database
- server. The database server appends this portion of the query to any portion you
- sent previously. Because the Database Access Manager and database server do not
- modify the string you send in any way, they do not insert any delimiter between
- fragments of queries that you send to the database server. If you want a blank
- or a semicolon to be included between query fragments, or if you want to use
- return characters to divide the query into lines of text, you must include them
- in the character string that you send with the DBSend function. The data string
- that you can send with the DBSend function can be any length up to 64 KB.
-
- The DBSendItem function sends a single data item to the remote database server.
- Use the DBSendItem function to send data items to the database in the same
- format as they are retrieved from the database by the DBGetItem function. You
- must specify the data type as an input parameter and, for any data type that
- does not have an implied length, you must specify the length as well. The
- database extension or the database server (depending on how the system is
- implemented) converts the data item to a character string and appends it to the
- query, just as a query program fragment is appended to the query by the DBSend
- function.
-
- You can call the DBSend and DBSendItem functions as many times as you wish to
- send your query to the database server.
-
- Listing 7-3 sends the CL/1 query fragment “print 451+222;” to the remote CL/1
- server.
-
- Listing 7-3. Sending a query fragment
-
- FUNCTION SendFragment (sessID: LongInt) : OSErr;
-
- VAR
- value1,value2: LongInt;
- text1, text2, text3: Str15;
- len1, len2, len3: Integer;
- rc: OSErr;
-
- BEGIN
- text1 := 'print ';
- len1 := LENGTH(text1);
- value1 := 451;
- text2 := '+';
- len2 := LENGTH(text2);
- value2 := 222;
- text3 := ';';
- len3 := LENGTH(text3);
- rc := DBSend(sessID, P2CStr(POINTER(ORD(@text1))), len1, NIL);
-
- IF rc = noErr THEN
- rc := DBSendItem(sessID, typeInteger, 0, 0, 0, POINTER(ORD(@value1)), NIL);
-
- IF rc = noErr THEN
- rc := DBSend(sessID, P2CStr(POINTER(ORD(@text2))), len2, NIL);
-
- IF rc = noErr THEN
- rc := DBSendItem(sessID, typeInteger, 0, 0, 0, POINTER(ORD(@value2)), NIL);
-
- IF rc = noErr THEN
- rc := DBSend(sessID, P2CStr(POINTER(ORD(@text3))), len3, NIL);
-
- SendFragment := rc;
- END;
-
- 4. Use the DBExec function to initiate execution of the query.
-
- Depending on the way the system you are using is implemented, the DBExec
- function might return control to your application as soon as the query has begun
- execution.
-
- 5. Use the DBState function to determine the status of the database.
-
- The DBState function tells you when the database has finished executing the
- query you just sent. If you have requested data, the database server stores the
- data you requested but does not send it to your application until you request it
- explicitly. The DBState function tells you when the data is available; go on to
- step 6. If you have just called the DBExec function to execute a query and wish
- to send another query, return to step 3. If you are finished using the database,
- skip to step 7.
-
- 6. Call the DBGetItem function repeatedly to retrieve the data.
-
- The DBGetItem function retrieves the next data item from the database server.
- You can also use this function to obtain information about the next data item
- without retrieving the data. When you use the DBGetItem function to retrieve a
- data item, you must specify the location and size of the buffer into which the
- function is to place that item. If you know beforehand what kind of data to
- expect, you can allocate a buffer of the exact size you need. If you do not know
- what type of data to expect, you can first call the DBGetItem function with a
- NIL pointer to the data buffer. The DBGetItem function then returns information
- about the next data item without actually retrieving it. You can then allocate
- the appropriate buffer and call DBGetItem again.
-
- Alternatively, to avoid calling DBGetItem twice for each data item, you can
- allocate a buffer that you expect to be of sufficient size for any data item and
- call the DBGetItem function. If the buffer is not large enough for the data
- item, the DBGetItem function returns the rcDBError result code, but still
- returns information about the data item. You can then allocate the necessary
- buffer, call the DBUnGetVal function to go back one data item, and call the
- DBGetItem function again to retrieve the data item a second time.
-
- The DBGetItem function includes a timeout parameter that you can use to specify
- the maximum amount of time that the database extension should wait to receive
- results from the database server before canceling the command. If the database
- extension you are using does not support asynchronous execution of routines, you
- can use the timeout parameter to return control to your application while a
- query is executing. To use the timeout parameter in this way, call the DBGetItem
- function periodically with a short value set for the timeout parameter. Your
- application can then retrieve the next data item as soon as execution of the
- query is complete without having to call the DBState function to determine when
- data is available. The DBGetItem function ignores the timeout parameter if you
- make an asynchronous call to this function.
-
- 7. When you are finished using the database, you must use the DBEnd function to
- terminate the session. You must call the DBEnd function after the DBInit
- function has returned a nonzero session ID, even if it also returned an error.
-
- 8. When you are finished using the Database Access Manager, call the QuitDBPack
- function to close the manager.
-
- Listing 7-4 uses the low-level interface to send a CL/1 routine to the CL/1
- server on a remote computer, and retrieves the results.
-
- Listing 7-4. Use of the low-level interface (TO BE PROVIDED)
-
- Note that, even if you are using the low-level interface to send queries to the
- database, you might want to use the high-level functions to retrieve data and
- convert it to text.
-
- _______________________________________________________________________________
-
- æKY Getting…Information…About…Sessions…in…Progress
- æC »Getting Information About Sessions in Progress Database Access Manager
- _______________________________________________________________________________
-
- If your application is only one of several on a single Macintosh computer using
- remote databases, you can use the DBGetConnInfo and DBGetSessionNum functions to
- obtain information about the sessions in progress. If you know the session ID
- (which is returned by the DBInit function when you open a session), you can use
- the DBGetConnInfo function to determine the database extension being used, the
- name of the remote system on which the session is running, the user name and
- connection string that were used to initiate the session, the time at which the
- session started, and the status of the session. The status of the session
- specifies whether the remote database server is executing a query or waiting for
- another query fragment, whether there is output data available, and whether
- execution of a query ended in an error.
-
- If you do not know the session ID, or if you want to get information about all
- open sessions, you can specify a database extension and a session number when
- you call the DBGetConnInfo function. Although there can be only one active
- session with a given session ID, session numbers are unique only for a specific
- database extension. Because the database extension assigns session numbers
- sequentially, starting with 1, you can call the DBGetConnInfo function
- repeatedly for a given database extension, incrementing the session number each
- time, to obtain information about all sessions open for that database extension.
- Your application need not have initiated the session to obtain information about
- it in this fashion.
-
- The DBGetSessionNum function returns the session number when you specify the
- session ID. You can use this function to determine the session numbers for the
- sessions opened by your own application. You might want this information, for
- example, so you can distinguish your own sessions from those opened by other
- applications when you use the DBGetConnInfo function to get information about
- all open sessions.
- _______________________________________________________________________________
-
- æKY Processing…Query…Results
- æC »Processing Query Results Database Access Manager
- _______________________________________________________________________________
-
- You can use the low-level function DBGetItem to retrieve a single data item
- returned by a query or you can use the high-level function DBGetQueryResults to
- retrieve all of the query results at once. If you use the DBGetQueryResults
- function, you can then use the DBResultsToText function to convert the results
- to ASCII text. The DBResultsToText function calls routines called result
- handlers, which are installed in memory by applications or by initialization
- routines. This section discusses the use of the DBGetItem and DBGetQueryResults
- functions and describes how to write and install a result handler.
-
- _______________________________________________________________________________
-
- æKY Getting…Query…Results
- æC »Getting Query Results Database Access Manager
- _______________________________________________________________________________
-
- The DBGetItem function retrieves a single data item that was returned by a
- database in response to a query. When you call the DBGetItem function, you
- specify the data type to be retrieved. If you do not know what data type to
- expect, you can specify the constant typeAnyType for the dataType parameter, and
- the database server returns the next data item regardless of data type. It also
- returns information about the data item, including data type and length.
- If you do not know the length of the next data item, you can specify NIL for the
- buffer parameter in the DBGetItem function, and the database server returns the
- data type, length, and number of decimal places without retrieving the data
- item. The next time you call the DBGetItem function with a nonzero value for the
- buffer parameter, the function retrieves the data item.
-
- If you want to skip a data item, specify the constant typeDiscard for the
- dataType parameter. Then the next time you call the DBGetItem function, it
- retrieves the following data item.
-
- You should use the DBGetItem function if you want complete control over the
- retrieval of each item of data. If you want the Database Access Manager to
- retrieve the data for you, use the DBGetQueryResults function instead.
-
- Table 7-2 shows the 4-byte code used by the Database Access Manager for each
- data type that is currently defined, and the values used for the dataType
- parameter in the DBGetItem function. The writer of a database extension can
- define other data types to support specific databases or database servers.
-
- Table 7-2. Data types, constants, and 4-byte codes
-
- Data type Constant Code
-
- any type typeAnyType $000000
- no more data expected typeNone 'none'
- Boolean typeBoolean 'bool'
- short integer typeSMInt 'smin'
- integer typeInteger 'int '
- short floating point typeSMFloat 'smfl'
- floating point typeFloat 'flot'
- date typeDate 'date'
- time typeTime 'time'
- date and time typeTimeStamp 'tims'
- character typeChar 'char'
- decimal number typeDecimal 'decm'
- money value typeMoney 'mony'
- variable character typeVChar 'vchr'
- variable binary typeVBin 'vbin'
- long character typeLChar 'lchr'
- long binary typeLBin 'lbin'
- discard next data item typeDiscard 'disc'
- unknown typeUnknown 'unkn'
- column break typeColBreak 'cbrk'
- end of line typeRowBreak 'rbrk'
-
- Each data type listed in Table 7-2 has a standard definition, shown in Table
- 7-3. For example, if the DBGetItem function returns the constant typeInteger for
- the dataType parameter, you know that the data item represents an integer value
- and that a 4-byte buffer is necessary to hold it. Similarly, if you are using
- DBSendItem function to send to the database server a data item that you identify
- as typeFloat, the database server expects to receive an 8-byte floating-point
- value.
-
- Notice that some of these data types are defined to have a specific length
- (referred to as an (implied length), and some do not. The len parameter of the
- DBSendItem and DBGetItem functions indicates the length of an individual data
- item. The DBGetQueryResults function returns a handle to an array of lengths,
- decimal places, and flags in the colInfo field of the results record.
-
- Table 7-3. Data types defined by the Database Access Manager
-
- Value of Length Definition
- dataType param
-
- typeAnyType NA Any data type (used as an input parameter to the
- DBGetItem function only; never returned by the
- function)
- typeNone 0 Empty
- typeBoolean 1 byte TRUE (1) or FALSE (0)
- typeSMInt 2 bytes Signed integer value
- typeInteger 4 bytes Signed long integer value
- typeSMFloat 4 bytes Signed floating-point value
- typeFloat 8 bytes Signed floating-point value
- typeDate 4 bytes Date; a long integer value consisting of a year
- (most significant 16 bits), month (8 bits), and day
- (least significant 8 bits)
- typeTime 4 bytes Time; a long integer value consisting of an hour
- (0–23; most significant 8 bits) minute (8 bits),
- second (8 bits), and hundredths of a second
- (least significant 8 bits)
- typeTimeStamp 8 bytes Date and time consisting of a long integer followed
- by a long integer time value
- typeChar any Fixed-length character string not NULL terminated.
- The length of the string is defined by the specific
- database.
- typeDecimal any Packed decimal string. A contiguous string of 4-bit
- nibbles, each of which contains a decimal number,
- except for the low nibble of the highest-addressed
- byte (that is, the last nibble in the string), which
- contains a sign. The value of the sign nibble can be
- 10, 12, 14, or 15 for a positive number or 11 or 13
- for a negative number; we recommend you use 12 for a
- positive number and 13 for a negative number. The most
- significant digit is the high-order nibble of the
- lowest-addressed byte (that is, the first nibble to
- appear in the string).
-
- The total number of nibbles (including the sign
- nibble) must be even; therefore, the high nibble of
- the highest-addressed byte of a number with an even
- number of digits must be 0.
-
- For example, the number +123 is represented as $123C
- and the number –1234 is represented as $01234D.
-
- The length of a packed decimal string is defined as
- the number of decimal digits in the string, not the
- number of bytes. Any extra leading zero and the sign
- nibble are not. Therefore, the number +123 has a
- length of 3 and the number –1234 has a length of 4.
- The length can have any value from 0 through 31.
-
- In addition to the length of a packed decimal string,
- each data item has an associated value that indicates
- the number of digits that follow the decimal place.
- The places parameter in the DBGetItem and DBSendItem
- functions indicates the number of decimal places in an
- individual data item. The DBGetQueryResults function
- returns the number of decimal places.
- typeMoney any Same as typeDecimal, but implies a currency amount.
- typeVChar any Variable-length character string, NULL terminated.
- typeVBin any Not defined. Reserved for future use.
- typeLChar any Not defined. Reserved for future use.
- typeLBin any Not defined. Reserved for future use.
- typeDiscard NA Do not retrieve the next data item (used as an input
- parameter to the DBGetItem function only; never
- returned by the function)
- typeUnknown NA A dummy data type for the result handler that
- processes any data type for which no other result
- handler is available (used as an input parameter to
- the DBInstallResultHandler, DBRemoveResultHandler,
- and DBGetResultHandler functions only; never returned
- by the DBGetItem or DBResultsToText functions)
- typeColBreak NA A dummy data type for the result handler that the
- DBGetQueryResults function calls after each item that
- is not the last item in a row (used as an input
- parameter to the DBInstallResultHandler,
- DBRemoveResultHandler, and DBGetResultHandler
- functions only; never returned by the DBGetItem or
- DBResultsToText functions)
- typeRowBreak NA A dummy data type for the result handler that the
- DBGetQueryResults function calls at the end of each
- row (used as an input parameter to the
- DBInstallResultHandler, DBRemoveResultHandler, and
- DBGetResultHandler functions only; never returned by
- the DBGetItem or DBResultsToText functions)
-
- The DBGetQueryResults function retrieves all of the data that was returned by a
- database in response to a query, unless insufficient memory is available to hold
- the data, in which case it retrieves as many complete rows of data as possible.
- The DBGetQueryResults function stores the data in a structure called a results
- record. The results record is defined by the ResultsRecord data type.
-
- TYPE ResultsRecord =
- RECORD
- numRows: Integer; {number of rows retrieved}
- numCols: Integer; {number of columns per row}
- colTypes: Handle; {type of data in each column}
- colData: Handle; {array of data items}
- colInfo: Handle {info about each data item}
- END;
-
- The numRows field in the results record indicates the total number of rows
- retrieved. If the DBGetQueryResults returns a result code other than rcDBValue,
- then not all of the data actually returned by the database was retrieved. This
- could happen, for instance, if the user’s computer does not have sufficient
- memory space to hold all the data. In this case, your application can make more
- space available (by writing the data in the data record to disk, for example)
- and then call the DBGetQueryResults function again to complete retrieval of the
- data.
-
- Note: The DBGetQueryResults function retrieves whole rows only; if it runs out
- of space in the middle of a row, it stores the partial row in a private buffer
- so that the data in the results record ends with the last complete row. Because
- the last partial row is no longer available from the remote database server, you
- cannot start to retrieve data with the DBGetQueryResults function and then
- switch to the DBGetItem function to complete the data retrieval.
-
- The numCols field indicates the number of columns in each row of data.
-
- The colTypes field is a handle to an array of data types, specifying the type of
- data in each column. The number of elements in the array is equal to the value
- in the numCols parameter. Table 7-2 shows the standard data types.
-
- The colData field is a handle to the data retrieved by the DBGetQueryResults
- function.
-
- The colInfo field is a handle to an array of records of type DBColInfoRecord,
- each of which specifies the length, places, and flags for a data item. There are
- as many records in the array as there are data items retrieved by the
- DBGetQueryResults function. Here is the DBColInforRecord type definition:
-
- TYPE DBColInfoRecord =
- RECORD
- len: Integer; {length of data item}
- places: Integer; {places for decimal and money data items}
- flags: Integer; {flags for data item}
- END;
-
- The len field indicates the length of the data item. The DBGetQueryResults
- function returns a value in this field only for those data types that do not
- have implied lengths; see Table 7-3.
-
- The places field indicates the number of decimal places in data items of types
- typeMoney and typeDecimal. For all other data types, the places field returns 0.
-
- If the flags field is set to kDBLastColFlag (that is, the least significant bit
- is set to 1), the data item is in the last column of the row.
- _______________________________________________________________________________
-
- æKY Converting…Query…Results…to…Text
- æC »Converting Query Results to Text Database Access Manager
- _______________________________________________________________________________
-
- The DBResultsToText function provided by the high-level interface converts the
- data retrieved by the DBGetQueryResults function into strings of ASCII text.
- This function makes it easier for you to display retrieved data for the user.
- For the DBResultsToText function to convert data of a specific type to text,
- either the application or the system software must have a routine called a
- result handler. With system software version 7.0, Apple Computer, Inc. is
- providing system result handlers for the data types listed in Table 7-4. These
- data types are described in Table 7-3:
-
- Table 7-4. Data types for which system result handlers are provided
-
- Data type Result handler Data type code
-
- Boolean typeBoolean 'bool'
- short integer typeSMInt 'smin'
- integer typeInteger 'int '
- short floating point typeSMFloat 'smfl'
- floating point typeFloat 'flot'
- character typeChar 'char'
- variable character typeVChar 'vchr'
-
- Note that Table 7-3 also defines several other data types for which Apple does
- not provide system result handlers.
-
- In addition to these standard data types, Apple is providing the system result
- handlers shown in Table 7-5.
-
- • typeUnknown
- • typeColBreak
- • typeRowBreak
-
- Table 7-5. Additional system result handlers
-
- Data type Result handler Data type code
-
- unknown typeUnknown 'unkn'
- column break typeColBreak 'cbrk'
- end of line typeRowBreak 'rbrk'
-
- The typeUnknown result handler processes any data type for which no other result
- handler is available. The DBResultsToText function calls the typeColBreak result
- handler after each item that is not the last item in a row. This result handler
- does not correspond to any data type, but adds a delimiter character to separate
- columns of text. The default typeColBreak result handler inserts a tab
- character. Similarly, the DBResultsToText function calls the typeRowBreak result
- handler at the end of each row of data to add a character that separates the
- rows of text. The default typeRowBreak result handler inserts a return
- character. Your application can install result handlers for the typeColBreak and
- typeRowBreak data types to insert whatever characters you wish—or to insert no
- character at all, if you prefer.
-
- You can install result handlers for any data types you know about. When you call
- the DBInstallResultHandler function, you can specify whether the result handler
- you are installing is a system result handler. A system result handler is
- available to all applications that use the system. All other result handlers
- (called application result handlers) are associated with a particular
- application. The DBResultsToText function always uses a result handler for the
- current application in preference to a system result handler for the same data
- type. When you install a system result handler with the same name as an already
- installed system result handler, the new result handler replaces the old one.
- Similarly, when you install an application result handler with the same name as
- a result handler already installed for the same application, the new result
- handler replaces the old one for that application.
-
- Result handlers are stored in memory. The Database Access Manager reinstalls its
- system result handlers each time the Macintosh Operating System loads the
- Database Access Manager package into memory. You must reinstall your own
- application result handlers each time your application starts up. You can also
- install your own system result handlers each time your application starts up, or
- you can provide an initialization file (that is, a file with a resource of type
- 'INIT' that is placed in the System Folder) that installs system result handlers
- each time the user starts up the system.
-
- Here is a function declaration for a result handler function.
-
- FUNCTION MyResultHandler (dataType: DBType; theLen,thePlaces, theFlags:
- Integer; theData: Ptr; theText: Handle) : OSErr;
-
- The dataType parameter specifies the data type of the data item that the
- DBResultsToText function is passing to the result handler. Table 7-3 describes
- the standard data types.
-
- The parameters theLen and thePlaces specify the length and number of decimal
- places of the data item that the DBResultsToText function wants the result
- handler to convert to text.
-
- The parameter theFlags is the value returned for the flags parameter by the
- DBGetItem function. If this parameter is set to kDBLastColFlag (that is, the
- least significant bit is set to 1), the data item is in the last column of the
- row.
-
- The parameter theData is a pointer to the data that the result handler is to
- convert to text.
-
- The parameter theText is a handle to the buffer that is to hold the text version
- of the data. The result handler should use the SetHandleSize function to
- increase the size of the buffer as necessary to hold the new text, and append
- the new text to the end of the text already in the buffer. The SetHandleSize
- function is described in the Memory Manager chapter of Volume II.
-
- If the result handler successfully converts the data to text, it should return a
- result code of 0 (noErr).
- You can use the DBInstallResultHandler function to install a result handler and
- the DBRemoveResultHandler function to remove an application result handler. You
- can install and replace system result handlers, but you cannot remove them.
-
- The following line of code installs an application result handler. The first
- parameter (typeMoney) specifies the data type that this result handler
- processes. The second parameter (moneyPtr) is a pointer to the result handler
- routine. The last parameter (FALSE) is a boolean specifying that this routine is
- not a system result handler.
-
- err := DBInstallResultHandler (typeMoney, moneyPtr, FALSE);
-
- Listing 7-5 shows a result handler that converts data to text.
-
- Listing 7-5. A result handler (TO BE PROVIDED)
-
- _______________________________________________________________________________
-
- æKY Creating…a…Query…Document
- æC »CREATING A QUERY DOCUMENT Database Access Manager
- _______________________________________________________________________________
-
- A query document is a file of type 'qery' that contains a 'qrsc' resource and
- one or more 'wstr' resources, and may contain a 'qdef' resource plus other
- resources. Query documents make it possible for you to write applications that
- can communicate with remote database servers without requiring familiarity with
- CL/1 or another database connectivity language. Because a query document is most
- useful if it can be used by many different applications, no query document
- should depend on the presence of a particular application in order to function.
-
- An application can call the DBGetNewQuery function to convert a 'qrsc' resource
- into a query record in memory. The query record points to a 'wstr' resource that
- contains a template for a query; it contains the database commands and data
- necessary to create a query, without any information that must be added by the
- user just before the query is sent. The 'qdef' resource contains a query
- definition function, which can modify the query record and the can complete the
- query template to create a complete query. The DBStartQuery function sends the
- query pointed to by a query record to a remote database server. This section
- describes the contents of a query document, describes query records, and defines
- the 'qrsc', 'wstr', and 'qdef' resources.
-
- _______________________________________________________________________________
-
- æKY Contents…of…a…Query…Document
- æC »Contents of a Query Document Database Access Manager
- _______________________________________________________________________________
-
- The query document must contain
-
- • a 'qrsc' resource, as defined in the next section, “Query Records and
- Query Resources”
-
- • a 'STR#' resource that contains the name of the database extension to be
- used, plus the host, user name, password, and connection string used by
- the DBInit function
-
- • one or more 'wstr' resources containing queries; that is, strings of
- commands and data that the DBSend function sends to the remote database
- server and that the DBExec function executes
-
- A 'wstr' resource consists of a 2-byte length field followed by a character
- string. (The w in 'wstr' refers to the length word as opposed to the length byte
- used in a 'STR ' resource.) Each 'wstr' resource contains one query (or one
- query template, to be modified by the query definition function before it is
- sent to the remote database server). The 'qrsc' resource includes an array that
- lists the resource ID numbers of all of the 'wstr' resources in the query
- document and an index into the array that specifies which one of the 'wstr'
- resources should be sent to the database server.
-
- In addition, the query document may contain
-
- • a 'qdef' resource that contains a query definition function
-
- • any resources needed by the query definition function, such as 'DLOG' and
- 'DITL' resources (which support dialog boxes)
-
- Figure 7-7 illustrates the relationship between a query document, the query
- record, and the query definition function. The following sections describe
- 'qrsc' resources, query records, and 'qdef' resources in detail.
-
- ø 7.7 Relationship between a query document, a query record, and a query
- definition function
- _______________________________________________________________________________
-
- æKY Query…Records…and…Query…Resources
- æC »Query Records and Query Resources Database Access Manager
- _______________________________________________________________________________
-
- The DBGetNewQuery function converts the 'qrsc' resource on disk into a query
- record in memory. The query definition function can then modify the query record
- before the application sends the query to the remote database server. This
- section describes a query record, and then defines the format of a 'qrsc'
- resource. The following section, “Writing a Query Definition Function,”
- describes 'qdef' resources and query definition functions.
-
- _______________________________________________________________________________
-
- æKY Query…Records
- æC »Query Records Database Access Manager
- _______________________________________________________________________________
-
- The QueryRecord data structure defines a query record.
-
- TYPE QueryRecord =
- Record
- version: Integer; {query record format version}
- id: Integer; {resource ID of 'qrsc'}
- queryProc: Handle; {handle to qdef}
- ddevName: Str63; {name of ddev}
- host: Str255; {name of remote computer}
- user: Str255; {name of user}
- password: Str255; {user's password}
- connStr: Str255; {connection string}
- currQuery: Integer; {current query}
- numQueries: Integer; {number of queries}
- queryList: QueryListHandle; {handles to queries}
- numRes: Integer; {number of resources}
- resList: ResListHandle; {list of resources}
- dataHandle: Handle; {handle to memory for qdef}
- refCon: LongInt {reserved for use by app}
- END;
-
- Field descriptions
- version
- The version number of the query record format. For the Database Access Manager
- released with system software version 7.0, the version number is 0.
-
- id
- The resource ID of the 'qrsc' resource from which the Database Access Manager
- created this query record.
-
- queryProc
- A handle to the query definition function that the DBStartQuery function calls.
- This handle is NIL if there is no query definition function; that is, if the
- DBStartQuery function should send the query specified by this query record to
- the remote database server without modifications.
-
- ddevName
- The database extension name used as a parameter to the DBInit function.
- host The name of the remote computer system used as a parameter to the DBInit
- function.
-
- user
- The name of the user, used as a parameter to the DBInit function.
-
- password
- The user’s password, used as a parameter to the DBInit function.
-
- connStr
- The connection string used as a parameter to the DBInit function.
-
- currQuery
- An index value from 1 through numQueries, indicating which element in the array
- of query handles represents the current query. The current query is the one
- actually sent to the database server. If the query document contains more than
- one 'wstr' resource, the query definition function can prompt the user to select
- a new current query and modify this field in the query record appropriately.
- numQueries The number of queries referred to by the queryList field.
-
- queryList
- A handle to an array of handles. Each handle in this array refers to a query.
- Each query is created from a 'wstr' resource in the query document and is stored
- in memory as a 2-byte length field followed by ASCII text. (The length does not
- include the 2 bytes of the length field.) The query definition function can
- create a new query. To add a new handle to the array of handles, use the Memory
- Manager’s SetHandleSize function to increase the size of the array. Don’t forget
- to change the value of the numQueries field as well.
-
- numRes
- The number of resources referred to by the resList field.
-
- resList
- A handle to an array of records of type ResListElem. Each record in the array
- contains the type and ID of a resource that is needed by the query definition
- function.
-
- TYPE ResListElem =
- RECORD
- TheType: ResType; {resource type}
- id: Integer {resource ID}
- END;
-
- dataHandle
- A handle to memory for use by the query definition function. When the Database
- Access Manager first creates the query record, this field is NIL. The query
- definition function can allocate memory and place a handle to it in this field.
- The query definition function should dispose of any memory it allocates before
- it returns control to the Database Access Manager.
-
- refCon
- The query record’s reference value. The application can use this field for any
- purpose.
-
- _______________________________________________________________________________
-
- æKY Query…Resources
- æC »Query Resources Database Access Manager
- _______________________________________________________________________________
-
- Here is the structure of the 'qrsc' resource, in the format used by the Rez
- resource compiler supplied with MPW.
-
- type 'qrsc' {
- Integer; /* version */
- Integer; /* ID of 'qdef' resource */
- Integer; /* ID of 'STR#' resource that contains ddevName, host, user, password,
- connection string */
- Integer; /* current query */
-
- /* Array of IDs of 'wstr' resources that contain queries */
-
- Integer = $$CountOf(QueryArray); /* array size */
- wide array QueryArray{
- Integer; /* ID of 'wstr' resource */
- };
-
- /* Array of resource types and IDs for other resources in the query document */
-
- Integer = $$CountOf(ResArray); /* array size */
- wide array ResArray{
- literal LongInt; /* resource type */
- Integer; /* resource ID */
- };
- };
-
- The first field in the 'qrsc' resource is the version number of the 'qrsc'
- format. For the Database Access Manager released with system software version
- 7.0, the version number is 0.
-
- The second field is the resource ID of the 'qdef' resource containing the query
- definition function that the Database Access Manager is to call when it opens
- this 'qrsc' resource. Use an ID of 0 if there is no query definition function
- for this resource; that is, if the Database Access Manager should send the query
- in this resource to the remote database server without modifications.
-
- The third field is the ID of a 'STR#' resource that contains five Pascal strings
- corresponding to the parameters used by the DBInit function. If the query
- definition function is going to prompt the user for the values of these
- parameters before entering them in the query record, they should be zero-length
- strings in the 'STR#' resource.
-
- The sixth field in the 'qrsc' resource is an array of ID numbers of the 'wstr'
- resources in the query document. The fifth field is the size of the array of
- 'wstr' IDs, and the fourth field is an index value indicating which element in
- the array of 'wstr' IDs represents the current query. (The array elements are
- numbered starting with 1.) The current query is the one actually sent to the
- database server. If the query document contains more than one 'wstr' resource,
- the query definition function can prompt the user to select the query to use and
- modify the current query field in the query record appropriately.
-
- The eighth field in the 'qrsc' resource is an array listing the resource types
- and IDs of all the resources in the query document other than the standard
- resources included in all query documents. The seventh field is the size of this
- array. The resources listed in this final array are those used by the query
- definition function. This list should include resources embedded in other
- resources, such as a 'PICT' resource that is included in a 'DITL' resource.
- _______________________________________________________________________________
-
- æKY Writing…a…Query…Definition…Function
- æC »Writing a Query Definition Function Database Access Manager
- _______________________________________________________________________________
-
- When the Database Access Manager creates a query record, it calls the query
- definition function specified by the queryProc field in the query record. The
- purpose of the query definition function is to modify the query and the query
- record before the query is sent to the remote database server. The query
- definition function can use dialog boxes to request information from the user.
- Because a query document is most useful if it can be used by many different
- applications, no query definition function should depend on the presence of a
- particular application.
-
- If you want to include a query definition function, you must make it the first
- piece of code in a resource of type 'qdef' in the query document.
- Here is a function declaration for a query definition function.
-
- FUNCTION myqdef (VAR sessID: LongInt; query: QueryHandle) : OSErr;
-
- If the application has already established a session with the remote database
- server, the DBStartQuery function passes the session ID for that session in the
- sessID parameter to the query definition function. If the query definition
- function receives a 0 in this parameter, then the Database Access Manager has
- not established a session. In this case, the query definition function can
- return a 0 in the sessID parameter, or it can call the DBInit function to
- establish a session and then return the session ID in this parameter.
- If the query definition function returns a 0 in the sessID parameter, the
- DBStartQuery function calls the DBInit function and then calls the DBSend
- function to send a query to the remote database server. If the query definition
- function returns a session ID in this parameter, the DBStartQuery function calls
- the DBSend function immediately.
-
- The query parameter to the query definition function specifies a handle to the
- query record. The query definition function can modify any of the fields in the
- query record, including the currQuery field that specifies which query is to be
- sent to the remote database server. In addition, the query definition function
- can modify an existing query or create a new query, adding the handle to the new
- query to the query list. Note that, because a query in memory consists only of a
- 2-byte length value followed by a character string, the query definition
- function has to know the exact contents and structure of a query in order to
- modify it.
-
- The query definition function must return the noErr result code as the function
- result if the function executed successfully. If it returns any other value, the
- DBStartQuery function does not call the DBSend function. The query definition
- function can return any result code, including
-
- noErr 0 No error
- userCanceledErr –128 User canceled the query
- rcDBError –802 Error executing query definition function
-
- When the DBStartQuery function calls the query definition function, the current
- resource file is the file that contains the 'qrsc' resource from which the
- Database Access Manager created the query record. When the query definition
- function returns control to the Database Access manager, the current resource
- file must be unchanged.
-
- The query definition function can allocate memory and use the dataHandle field
- in the query record to store a handle to it; the function can also use the
- refCon field in the query record for any purpose. The query definition function
- must free any memory it allocates before terminating.
-
- Listing 7-6 shows a query definition function.
-
- Listing 7-6. A query definition function (TO BE PROVIDED)
-
- _______________________________________________________________________________
-
- æKY Database…Access…Manager…Routines
- æC »DATABASE ACCESS MANAGER ROUTINES Database Access Manager
- _______________________________________________________________________________
-
- The Database Access Manager has high-level routines, low-level routines, and
- routines that manipulate result handlers. This section describes all of the
- Database Access Manager routines.
-
- All of the low-level routines and some of the high-level routines have as a
- parameter a pointer to an asynchronous parameter block. If you specify a nonzero
- value for this parameter, the database extension executes the function
- asynchronously; that is, it returns control to the Database Access Manager
- before the routine has completed execution, and the Database Access Manager
- returns control to your application. If you specify NIL for the pointer to the
- asynchronous parameter block, the database extension does not return control to
- your application until the routine has finished execution.Your application must
- call the WaitNextEvent routine periodically to allow an asynchronous routine to
- complete execution. The WaitNextEvent routine is described in the Event Manager
- chapter of this volume.
-
- You can tell when an asynchronous routine has completed execution and check the
- result code by looking at values in the asynchronous parameter block. The
- asynchronous parameter block is described in the next section, “Asynchronous
- Execution of Routines.”
-
- Note: A noErr result code returned by a routine that has been called
- asynchronously indicates only that the routine began execution successfully. You
- must check the result field of the asynchronous parameter block for the final
- result of the routine.
-
- Assembly-language note: You can invoke each of the Database Access Manager
- routines with a macro that has the same name as the routine, but preceded with
- an underscore; for example, the macro for the DBInit function is named _DBInit.
- Each of these macros places a routine selector in the D0 register and calls the
- trap _Pack13. The routine selectors are listed in “Summary of the Database
- Access Manager” at the end of this chapter.
-
- _______________________________________________________________________________
-
- æKY Asynchronous…Execution…of…Routines
- æC »Asynchronous Execution of Routines Database Access Manager
- _______________________________________________________________________________
-
- Each Database Access Manager routine that can be called asynchronously (that is,
- that can return control to your application before it has completed execution)
- takes as a parameter a pointer to a parameter block known as the asynchronous
- parameter block. If this pointer is NIL, the routine does not return control to
- your application until it has completed execution.
-
- Note: The asynchronous parameter block is passed on to the database extension,
- which is responsible for implementing the asynchronous routine. If the database
- extension does not support asynchronous routines, the Database Access Manager
- returns a result code of rcDBAsyncNotSupp and terminates execution of the
- routine.
-
- The DBAsyncParamBlockRec data type defines the asynchronous parameter block.
-
- TYPE DBAsyncParamBlockRec =
- RECORD
- completionProc: ProcPtr; {pointer to completion routine}
- result: OSErr; {result of call}
- userRef: LongInt; {reserved for use by application}
- ddevRef: LongInt; {reserved for use by ddev}
- reserved: LongInt {reserved for use by Database Access Mgr}
- END;
-
- DBAsyncParmBlkPtr = ^DBAsyncParamBlockRec;
-
- The completionProc field is a pointer to a completion routine that the database
- extension calls when it has completed executing the asynchronous function.
- Before calling the completion routine, the database extension places a pointer
- to the asynchronous parameter block in the A0 register. If you do not want to
- use a completion routine, set this parameter to NIL.
-
- The database extension sets the result field to 1 while the routine is
- executing, and places the result code in it when the routine completes. An
- application can poll this field to determine when an asynchronous routine has
- completed execution.
-
- The userRef field is reserved for the application’s use. Because the database
- extension passes a pointer to the parameter block to the completion routine, you
- can use this field to pass information to the completion routine.
-
- The ddevRef field is reserved for use by the database extension, and the
- reserved field is reserved for use by the Database Access Manager.
-
- You can use the DBKill function to cancel an asynchronous routine.
-
- _______________________________________________________________________________
-
- æKY Initializing…and…Closing…the…Database…Access…Manager
- æC »Initializing and Closing the Database Access Manager Database Access Manager
- _______________________________________________________________________________
-
- You must call the InitDBPack function before you call any other Database Access
- Manager routines. You must call the QuitDBPack function when you are finished
- using the Database Access Manager.
-
- FUNCTION InitDBPack : OSErr;
-
- The InitDBPack function causes the Package Manager to load the Database Access
- Manager into memory, if it has not already done so, and increments the Database
- Access Manager use counter. The use counter prevents any application from
- removing the Database Access Manager from memory while another application is
- using it.
-
- The interface routine that implements the InitDBPack function includes a version
- number for the Database Access Manager. If the package is a different version
- than specified by the interface routine, then the InitDBPack function returns
- the rcDBWrongVersion result code.
-
- Result codes
- noErr 0 No error
- rcDBWrongVersion –814 Wrong version number
-
- FUNCTION QuitDBPack : OSErr;
-
- The QuitDBPack function decrements the Database Access Manager use counter. When
- this counter equals 0, the QuitDBPack function removes the Database Access
- Manager package from memory. Call this routine when your application is
- terminating or when you are finished using the Database Access Manager. The use
- counter prevents the QuitDBPack function from removing the Database Access
- Manager from memory while any application is still using it.
-
- Result codes
- noErr 0 No error
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
- _______________________________________________________________________________
-
- æKY High-Level…Interface
- æC »High-Level Interface Database Access Manager
- _______________________________________________________________________________
-
- The high-level interface to the Database Access Manager enables applications to
- manipulate query documents and to get the results of the query provided by a
- query document. The use and contents of query documents are discussed in
- “Creating a Query Document” earlier in this chapter.
-
- _______________________________________________________________________________
-
- æKY Handling…Query…Documents
- æC »Handling Query Documents Database Access Manager
- _______________________________________________________________________________
-
- The routines described in this section open query documents, create query
- records, dispose of query records, and use query documents to establish
- communication with and send queries to a remote database server.
-
- FUNCTION DBGetNewQuery (queryID: Integer; VAR query: QueryHandle) : OSErr;
-
- The DBGetNewQuery function creates a query record from the 'qrsc' resource with
- the resource ID you specify in the queryID parameter. The resource file that
- contains the 'qrsc' resource must remain open until after the DBStartQuery
- function has completed execution. If you do not already know the resource ID of
- the 'qrsc' resource (for example, if you call the SFGetFile procedure to let the
- user select the query document), you can use Resource Manager routines to
- determine the resource ID. The SFGetFile procedure is described in the Standard
- File Package chapter of Volume I and the Resource Manager is described in Volume
- Chapter 5.
-
- The queryID parameter specifies the resource ID of the 'qrsc' resource that you
- want to use. The query parameter returns a handle to the query record.
-
- Result code
- noErr 0 Query record built successfully
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- FUNCTION DBDisposeQuery (query: QueryHandle) : OSErr;
-
- The DBDisposeQuery function disposes of a query record and frees all the memory
- that the Database Access Manager allocated when it created the query record. You
- should call this function after you are finished using a query record.
-
- The query parameter is a handle to the query record.
-
- Result code
- noErr 0 Query record disposed of successfully
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- FUNCTION DBStartQuery (VAR sessID: LongInt; query: QueryHandle; statusProc:
- ProcPtr; asyncPB: DBAsyncParmBlkPtr) : OSErr;
-
- The DBStartQuery function performs the following tasks, in the order specified:
-
- 1. It calls the query definition function (if any) pointed to by the query
- record. The query definition function modifies the query record and the query,
- usually by asking the user for input. The query definition function can display
- a dialog box that gives the user the option of canceling the query; if the user
- does cancel the query, the DBStartQuery function returns the userCanceledErr
- result code.
-
- 2. If you specify a nonzero value for the statusProc parameter, the
- DBStartQuery function calls your status routine with the value kDBUpdateWind in
- the message parameter so that your application can update its windows.
-
- 3. If you specify a nonzero value for the statusProc parameter, the
- DBStartQuery function calls your status routine with the value kDBAboutToInit in
- the message parameter so that your application can display a dialog box
- informing the user that a database session is about to be established, and
- giving the user the option of canceling execution of the function.
-
- 4. If the sessID parameter is 0, the DBStartQuery function calls the DBInit
- function to establish a database session, and returns a session ID.
-
- 5. If you specify a nonzero value for the statusProc parameter and the
- DBStartQuery function called the DBInit function, the DBStartQuery function
- calls your status routine with the value kDBInitComplete in the message
- parameter and the result of the DBInit function in the result parameter.
-
- 6. The DBStartQuery function calls the DBSend function to send the query to the
- remote database server.
-
- 7. If you specify a nonzero value for the statusProc parameter, the
- DBStartQuery function calls your status routine with the value kDBSendComplete
- in the message parameter and the result of the DBSend function in the result
- parameter.
-
- 8. The DBStartQuery function calls the DBExec function to execute the query.
-
- 9. If you specify a nonzero value for the statusProc parameter, the
- DBStartQuery function calls your status routine with the value kDBExecComplete
- in the message parameter and the result of the DBExec function in the result
- parameter.
-
- 10. If you specify a nonzero value for the statusProc parameter, the
- DBStartQuery function calls your status routine with the value
- kDBStartQueryComplete in the message parameter and the result of the
- DBStartQuery function in the result parameter.
-
- You can use the sessID parameter to specify a session ID if your application or
- another application has already established a session with the database server.
- If you specify NIL for this parameter, then the DBStartQuery function
- establishes a session and returns the session ID in the sessID parameter.
-
- You use the query parameter to specify a handle to a query record.
- You can use the statusProc pointer to specify a pointer to a status routine that
- your application can use to update its windows after the query definition
- function has completed execution. If you specify NIL for this parameter, the
- DBStartQuery function does not attempt to update your application’s windows. The
- DBStartQuery function also calls your status routine before it initiates a
- database session, after it calls the DBInit function, after it calls the DBSend
- function, and after it calls the DBExec function. Status routines are discussed
- in “Writing a Status Routine for High-Level Functions” earlier in this chapter.
-
- If you specify a pointer to an asynchronous parameter block in the asyncPB
- parameter, the DBStartQuery function calls the DBInit, DBSend, and DBExec
- functions asynchronously. As soon as the DBInit function has started execution,
- it returns control to your application. Your application must then call the
- WaitNextEvent routine periodically to allow these asynchronous routines to run,
- and it must check the result field of the asynchronous parameter block to
- determine when each routine has completed execution.
-
- Result codes
- noErr 0 No error
- userCanceledErr –128 User canceled the query
- rcDBError –802 Error initiating session, sending text, or executing
- query
- rcDBBadDDev –809 Couldn’t find the specified database extension, or
- error occurred in opening database extension
- rcDBAsyncNotSupp –811 The database extension does not support asynchronous
- calls
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- _______________________________________________________________________________
-
- æKY Handling…Query…Results
- æC »Handling Query Results Database Access Manager
- _______________________________________________________________________________
-
- The routines in this section retrieve query results and convert them to text.
-
- FUNCTION DBGetQueryResults (sessID: LongInt; VAR results: ResultsRecord;
- timeout: LongInt; statusProc: ProcPtr;
- asyncPB: DBAsyncParmBlkPtr) : OSErr;
-
- The DBGetQueryResults function retrieves the results returned by a query and
- places them in memory. If there is sufficient memory available, this function
- retrieves all of the results at once. If the DBGetQueryResults function runs out
- of memory, it places as much data as possible in memory, up to the last whole
- row. You can then make more memory available and call the DBGetQueryResults
- function again to retrieve more data.
-
- The DBGetQueryResults function can be used to retrieve the results of any query,
- not only queries sent and executed by the DBStartQuery function.
-
- The sessID parameter specifies the ID of the session from which you wish to
- retrieve results.
- The results parameter is the results record, which contains a handle to the
- retrieved data. Results records are described in “Getting Query Results” earlier
- in this chapter.
-
- The timeout parameter specifies the value that he DBGetQueryResults uses for the
- timeout parameter each time it calls the DBGetItem function. The timeout
- parameter specifies the maximum amount of time that the database extension
- should wait to receive results from the database server before canceling the
- DBGetItem function. Specify the timeout parameter in sixtieths of a second. To
- disable the timeout feature, set the timeout parameter to the value
- kDBWaitForever. This parameter is ignored if you specify a nonzero value for the
- asyncPB parameter.
-
- You can use the statusProc pointer to specify a pointer to a status routine that
- you provide. The DBGetQueryResults function calls your status routine after it
- calls the DBGetItem function to retrieve a data item. When it calls the status
- routine, the DBGetQueryResults function provides the results of the DBGetItem
- function, the data type, the data length, number of decimal places, and flags
- associated with the data item, and a pointer to the data item. Status routines
- are discussed in “Writing a Status Routine For High-Level Functions” earlier in
- this chapter.
-
- If you specify a pointer to an asynchronous parameter block in the asyncPB
- parameter, the DBGetQueryResults function calls the DBGetItem function
- asynchronously for each data item. As soon as the DBGetItem function has started
- execution, it returns control to your application. Your application must then
- call the WaitNextEvent routine periodically to allow this asynchronous routine
- to run, and it must check the result field of the asynchronous parameter block
- to determine when the routine has completed execution.
-
- Result codes
- noErr 0 Query execution successful; no results returned
- userCanceledErr –128 Function canceled by status routine
- rcDBValue –801 Data available
- rcDBError –802 Query execution ended in an error
- rcDBBreak –805 Function timed out
- rcDBExec –806 Query currently executing
- rcDBBadSessID –807 Session ID is invalid
- rcDBAsyncNotSupp –811 The database extension does not support
- asynchronous calls
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- FUNCTION DBResultsToText (results: ResultsRecord; VAR theText: Handle) : OSErr;
-
- The DBResultsToText function calls result handlers to convert to text the data
- retrieved by the DBGetQueryResults function. Result handlers are described in
- “Converting Query Results to Text” earlier in this chapter.
-
- The results parameter is the results record returned by the DBGetQueryResults
- function. The parameter theText contains a handle to the converted text. This
- handle is allocated by the Database Access Manager.
-
- Result code
- noErr 0 No error
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
- _______________________________________________________________________________
-
- æKY Low-Level…Interface
- æC »Low-Level Interface Database Access Manager
- _______________________________________________________________________________
-
- The low-level interface to the Database Access Manager enables applications to
- open and close sessions with a remote database server, send and execute queries,
- retrieve query results, and obtain information about any current session.
- _______________________________________________________________________________
-
- æKY Controlling…the…Session
- æC »Controlling the Session Database Access Manager
- _______________________________________________________________________________
-
- The functions in this section initiate and close sessions, obtain information
- about sessions, and cancel functions that were called asynchronously.
-
- FUNCTION DBInit (VAR sessID: LongInt; ddevName: Str63; host, user, password,
- connStr: Str255; asyncPB: DBAsyncParmBlkPtr) : OSErr;
-
- The DBInit function initiates a session with a remote database server. You must
- initiate a session before you call any Database Access Manager function that
- requires a session ID as an input parameter. If the DBInit function returns a
- nonzero session ID, you must call the DBEnd function to terminate the session,
- even if the DBInit function also returns a result code other than noErr.
-
- Because the high-level function DBStartQuery can call the DBInit function, if
- you have called the DBStartQuery function, you do not have to call the DBInit
- function.
-
- The DBInit function returns the session ID in the sessID parameter. This session
- ID is unique; no other current session, for any database extension, has the same
- session ID. You must specify the session ID any time you want to send data to or
- retrieve data from this session. Depending on the database extension you are
- using, the DBInit function might return a session ID of 0 if it fails to
- initiate a session, or it might return a nonzero session ID and a result code
- other than noErr. In the latter case, you can pass the session ID to the
- DBGetErr function to determine the cause of the error.
-
- The ddevName parameter is a string of no more than 63 characters that specifies
- the name of the database extension. The name of the database extension is
- contained in the database extension file in a resource of type 'STR ' with an ID
- of 128. For the CL/1 database extension provided by Apple , for example, this
- string is “CL/1”.
-
- The host parameter specifies the name of the remote system on which the database
- server is located. This name depends on the manner in which the database
- extension establishes communication with the remote database server and on how
- the system administrator has set up the computer system.
-
- The user parameter specifies the name of the user, and the password parameter
- specifies the password associated with the user name.
-
- The connStr parameter is a connection string that is passed to the database
- server, which might pass it on to the database management software on the remote
- computer. This string is necessary in some systems to complete log-on
- procedures.
- The asyncPB parameter is a pointer to the asynchronous parameter block. If you
- do not want to call the function asynchronously, set this parameter to NIL.
-
- Result codes
- noErr 0 No error
- rcDBError –802 Error initiating session
- rcDBBadDDev –809 Couldn’t find specified database extension or
- trouble opening ddev file
- rcDBAsyncNotSupp –811 Asynchronous calls are not supported by
- database extension
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- FUNCTION DBEnd (sessID: LongInt; asyncPB: DBAsyncParmBlkPtr) : OSErr;
-
- The DBEnd function terminates a session with a remote database server and
- terminates the network connection between the application and the remote
- computer. You must call the DBEnd function to terminate a session.
-
- The sessID parameter is the session ID that was returned by the DBInit function.
-
- The asyncPB parameter is a pointer to the asynchronous parameter block. If you
- do not want to call the function asynchronously, set this parameter to NIL.
-
- Result codes
- noErr 0 No error
- rcDBError –802 Error ending session
- rcDBBadSessID –807 Session ID is invalid
- rcDBAsyncNotSupp –811 Asynchronous calls are not supported by
- database extension
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- FUNCTION DBGetConnInfo (sessID: LongInt; sessNum: Integer; VAR returnedID,
- version: LongInt; VAR ddevName: Str63; VAR host, user,
- network, connStr: Str255; VAR start: LongInt; VAR state:
- OSErr; asyncPB: DBAsyncParmBlkPtr) : OSErr;
-
- The DBGetConnInfo function returns information about the specified session,
- including
-
- • the version of the database extension
- • the name of the remote system on which the session is running
- • the user name
- • the connection string that was used to establish communication
- • the name of the network
- • the time at which the session started, in ticks
- • the status of the session
-
- In addition, if you include a nonzero value for the sessID parameter when you
- call the DBGetConnInfo function, the function returns the name of the database
- extension. If you use 0 for the sessID parameter and specify the database
- extension and session number instead, the function returns the session ID.
-
- You can use this function to get information about a particular session, or you
- can call the function repeatedly, incrementing the session number each time, to
- get information about all of the sessions associated with a particular database
- extension.
-
- The sessID parameter is the session ID that was returned by the DBInit function.
- The sessNum parameter is the session number of the session about which you want
- information. You can specify either the session ID or the session number when
- you call the DBInit function. If you specify the sessID parameter, use 0 for the
- sessNum parameter. If you specify the sessNum parameter, then use 0 for the
- sessID parameter. If you specify the sessNum parameter, you must specify a value
- for the ddevName parameter as well. If you specify the session number and the
- database extension, then the DBGetConnInfo function returns the session ID in
- the returnedID parameter.
-
- The version parameter returns the version number of the database extension that
- is the interface to the remote database server on which this session is running.
-
- The ddevName parameter specifies the name of the database extension. If you
- specify 0 for the session ID, you must include the name of the database
- extension as well as a session number. If you specify a valid session ID, then
- the DBGetConnInfo function returns the name of the database extension in the
- ddevName parameter. The name of the database extension is included in a 'STR '
- resource in the database extension file with a resource ID of 128.
-
- The host, user, and connStr parameters are the host, user, and connection
- strings that were used to establish communication with the remote database
- server. The network parameter is the name of the network through which your
- computer is communicating with the remote database server.
-
- The start parameter is the time, in ticks, at which this session was initiated.
-
- The state parameter returns one of the following values to provide information
- about the status of the session:
-
- CONST
- noErr = 0 ;No error; ready for more text
- rcDBValue = –801 ;Output data available
- rcDBError = –802 ;Execution ended in an error
- rcDBExec = –806 ;Busy; currently executing query
-
- The asyncPB parameter is a pointer to the asynchronous parameter block. If you
- do not want to call the function asynchronously, set this parameter to NIL.
-
- Result codes
- noErr 0 No error
- rcDBBadSessNum –808 Invalid session number
- rcDBBadSessID –807 Session ID is invalid or database extension name is
- invalid
- rcDBBadDDev –809 Couldn’t find specified database extension or
- trouble opening ddev file
- rcDBAsyncNotSupp –811 Asynchronous calls are not supported by
- database extension
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- FUNCTION DBGetSessionNum (sessID: LongInt; VAR sessNum: Integer;
- asyncPB: DBAsyncParmBlkPtr) : OSErr;
-
- The DBGetSessionNum function returns the session number of the session you
- specify with the session ID parameter. The session number is unique for a
- particular database extension, but the same session number might be in use for
- different database extensions at the same time.
-
- The asyncPB parameter is a pointer to the asynchronous parameter block. If you
- do not want to call the function asynchronously, set this parameter to NIL.
-
- Result codes
- noErr 0 No error
- rcDBBadSessID –807 Session ID is invalid
- rcDBAsyncNotSupp –811 Asynchronous calls are not supported by
- database extension
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- FUNCTION DBKill (asyncPB: DBAsyncParmBlkPtr) : OSErr;
-
- The DBKill function cancels the execution of the asynchronous call specified by
- the asyncPB parameter.
-
- The asyncPB parameter is a pointer to the asynchronous parameter block.
-
- Result codes
- noErr 0 Asynchronous routine canceled successfully
- rcDBError –802 Error canceling routine
- rcDBBadAsynchPB –812 Invalid parameter block specified
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
- _______________________________________________________________________________
-
- æKY Sending…and…Executing…Queries
- æC »Sending and Executing Queries Database Access Manager
- _______________________________________________________________________________
-
- The functions in this section send queries or portions of queries to the remote
- database server, execute a query that has been sent, return information about
- queries that have been sent, and halt execution of queries that are executing.
-
- FUNCTION DBSend (sessID: LongInt; text: Ptr; len: Integer; asyncPB:
- DBAsyncParmBlkPtr) : OSErr;
-
- The DBSend function sends a query or a portion of a query to the remote database
- server. The database server appends this portion of the query to any portion you
- sent previously. Because the Database Access Manager and database server do not
- modify the string you send in any way, they do not insert any delimiter between
- fragments of queries that you send to the database server. If you want a blank
- or a semicolon to be included between query fragments, or if you want to use
- return characters to divide the query into lines of text, you must include them
- in the character string that you send with this function.
-
- The database server does not execute the query until you call the DBExec
- function.
-
- The sessID parameter is the session ID that was returned by the DBInit function.
-
- The text parameter is a pointer to the query or query fragment that you want to
- send to the database server. The query or query fragment must be a character
- string. The len parameter specifies the length of the character string. If the
- len parameter has a value of –1, then the character string is assumed to be
- “NULL terminated” (that is, the string ends with a NULL byte); otherwise, the
- len parameter specifies the number of bytes in the string.
-
- The asyncPB parameter is a pointer to the asynchronous parameter block. If you
- do not want to call the function asynchronously, set this parameter to NIL.
-
- Result codes
- noErr 0 No error
- rcDBError –802 Error trying to send text
- rcDBBadSessID –807 Session ID is invalid
- rcDBAsyncNotSupp –811 Asynchronous calls are not supported by
- database extension
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- FUNCTION DBSendItem (sessID: LongInt; dataType: DBType; len, places, flags:
- Integer; buffer: Ptr; asyncPB: DBAsyncParmBlkPtr) : OSErr;
-
- The DBSendItem function sends a single data item to the remote database server.
- You can use this function to send to the database server the data that you wish
- to include in a query. The database extension or the database server (depending
- on how the system is implemented) converts the data item to a character string
- and appends it to the query, just as a query program fragment is appended to the
- query by the DBSend function. The query is not executed until you call the
- DBExec function.
-
- The sessID parameter is the session ID that was returned by the DBInit function.
-
- The dataType, len, and places parameters specify the data type, length, and
- number of decimal places for the data item that you are sending to the remote
- database server. The database extension and database server ignore the len
- parameter if the data type has an implied length. The database extension and
- database server ignore the places parameter for all values of the dataType
- parameter except typeDecimal and typeMoney. Data types are discussed in “Getting
- Query Results” earlier in this chapter.
-
- The buffer parameter is a pointer to the memory location of the data item that
- you want to send. When you use the DBSendItem function to send an item of data
- to a database server, the database extension and database server format the data
- according to the data type, length, and decimal places you specified, converts
- it to a character string, and appends the data to the query.
-
- Set the flags parameter to 0. There are no flags currently defined for the
- DBSendItem function.
-
- The asyncPB parameter is a pointer to the asynchronous parameter block. If you
- do not want to call the function asynchronously, set this parameter to NIL.
-
- Result codes
- noErr 0 No error
- rcDBError –802 Error trying to send item
- rcDBBadSessID –807 Session ID is invalid
- rcDBAsyncNotSupp –811 Asynchronous calls are not supported by
- database extension
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- FUNCTION DBExec (sessID: LongInt; asyncPB: DBAsyncParmBlkPtr) : OSErr;
-
- The DBExec function initiates execution of a query that you have sent to the
- remote database server. Use the DBSend and DBSendItem functions to send a query
- to the database server. Use the DBState function to determine the status of a
- query after you have initiated execution.
-
- The sessID parameter is the session ID that was returned by the DBInit function.
-
- The asyncPB parameter is a pointer to the asynchronous parameter block. If you
- do not want to call the function asynchronously, set this parameter to NIL.
-
- Result codes
- noErr 0 Execution has begun
- rcDBError –802 Error trying to begin execution
- rcDBBadSessID –807 Session ID is invalid
- rcDBAsyncNotSupp –811 Asynchronous calls are not supported by
- database extension
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- FUNCTION DBState (sessID: LongInt; asyncPB: DBAsyncParmBlkPtr) : OSErr;
-
- The result code returned by the DBState function indicates the status of the
- remote database server. You can use this function to determine whether the
- database server has successfully executed a query and whether it has data
- available for you to retrieve.
-
- The sessID parameter is the session ID that was returned by the DBInit function.
-
- The asyncPB parameter is a pointer to the asynchronous parameter block. If you
- do not want to call the function asynchronously, set this parameter to NIL.
-
- Result codes
- noErr 0 No error; ready for more text
- rcDBValue –801 Output data available
- rcDBError –802 Execution ended in an error
- rcDBExec –806 Currently executing query
- rcDBBadSessID –807 Session ID is invalid
- rcDBAsyncNotSupp –811 Asynchronous calls are not supported by
- database extension
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- FUNCTION DBGetErr (sessID: LongInt; VAR err1,err2: LongInt; VAR item1, item2,
- errorMsg: Str255; asyncPB: DBAsyncParmBlkPtr) : OSErr;
-
- The DBGetErr function retrieves error codes and error messages from a remote
- database server. You can use this function to obtain information when a
- low-level function returns the result code rcDBError. If the DBState function
- returns the rcDBError result code, indicating that execution of a query ended in
- an error, the error information can help you debug the query. The meaning of
- each error code and error message returned by this function depends on the
- database server with which you are communicating; see the documentation for that
- database server for more information.
-
- The sessID parameter is the session ID that was returned by the DBInit function.
-
- The err1 and err2 parameters return the primary and secondary error codes. The
- item1 and item2 parameters return strings that describe the objects of the error
- message. The errorMsg parameter returns the error message.
-
- The asyncPB parameter is a pointer to the asynchronous parameter block. If you
- do not want to call the function asynchronously, set this parameter to NIL.
-
- Result codes
- noErr 0 No error
- rcDBError –802 Error retrieving error information
- rcDBBadSessID –807 Session ID is invalid
- rcDBAsyncNotSupp –811 Asynchronous calls are not supported by
- database extension
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- FUNCTION DBBreak (sessID: LongInt; abort: Boolean; asyncPB: DBAsyncParmBlkPtr) :
- OSErr;
-
- The DBBreak function can halt execution of a query and reinitialize the remote
- database server, or it can unconditionally terminate a session with a database
- server. You can use this function to cancel a query if you determine that it is
- taking too long to complete execution, for example.
-
- The sessID parameter is the session ID that was returned by the DBInit function.
-
- If the abort parameter is TRUE (nonzero), the database server halts any query
- that is executing and terminates the current session. If the abort parameter is
- FALSE (0), the database server halts any query that is executing and
- reinitializes itself.
-
- The asyncPB parameter is a pointer to the asynchronous parameter block. If you
- do not want to call the function asynchronously, set this parameter to NIL.
-
- Result codes
- noErr 0 Execution has begun
- rcDBError –802 Break or abort attempt was unsuccessful
- rcDBBadSessID –807 Session ID is invalid
- rcDBAsyncNotSupp –811 Asynchronous calls are not supported by
- database extension
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
- _______________________________________________________________________________
-
- æKY Retrieving…Results
- æC »Retrieving Results Database Access Manager
- _______________________________________________________________________________
-
- The functions in this section allow you to retrieve a data item from the
- database server, to obtain information about the next data item, and to retrieve
- the same data item more than once.
-
- FUNCTION DBGetItem (sessID: LongInt; timeout: LongInt; VAR dataType: DBType; VAR
- len,places,flags: Integer; buffer: Ptr; asyncPB:
- DBAsyncParmBlkPtr) : OSErr;
-
- The DBGetItem function retrieves the next data item from the database server.
- You can also use this function to obtain information about the next data item
- without retrieving the data. You can use the DBGetItem function after you have
- executed a query and the DBState function has returned the result code
- rcDBValue, indicating that data is available. You can repeat the DBGetItem
- function as many times as is necessary to retrieve all of the data returned by
- the database in response to a query.
-
- The sessID parameter is the session ID that was returned by the DBInit function.
-
- You can use the timeout parameter to specify the maximum amount of time that the
- database extension should wait to receive results from the database server
- before canceling the function. Specify the timeout parameter in sixtieths of a
- second. To disable the timeout feature, set the timeout parameter to the value
- kDBWaitForever. If the timeout period expires, the DBGetItem function returns
- the result code rcDBBreak. The DBGetItem function ignores the timeout parameter
- if you call the function asynchronously.
-
- One use for the timeout parameter is to call the DBGetItem function periodically
- with a short value set for this parameter in order to return control to your
- application while a query is executing. Your application can then retrieve the
- next data item as soon as execution of the query is complete without having to
- call the DBState function to determine when data is available.
-
- You can set the dataType parameter to specify the data type that you expect the
- next data item to be. If the item is not of the expected data type, the database
- extension returns the rcDBBadType result code. If you want to retrieve the next
- data item regardless of type, set the dataType parameter to the value
- typeAnyType. To skip the next data item, set the dataType parameter to the value
- typeDiscard. The database server sets the dataType parameter to the actual type
- of the data item when it retrieves the data item or returns information about
- the data item. Data types are discussed in “Getting Query Results” earlier in
- this chapter.
-
- Set the len parameter to the length of the data buffer pointed to by the buffer
- parameter. If you use the DBGetItem function to obtain information only (by
- setting the buffer parameter to NIL), then the database server ignores the len
- parameter. The database server sets the len parameter to the actual length of
- the data item when it retrieves the data item or returns information about the
- data item.
-
- The database server returns in the places parameter the number of decimal places
- in data items of types typeMoney and typeDecimal. For all other data types, the
- database server returns 0 for the places parameter.
-
- The buffer parameter is a pointer to the location where you want the retrieved
- data item to be stored. You must ensure that the location you specify contains
- enough space for the data item that will be returned. To determine the data
- type, length, and number of decimal places of the next data item without
- retrieving it, specify NIL for the buffer parameter.
-
- If the flags parameter is set to kDBLastColFlag (that is, the least significant
- bit is set to 1), the data item is in the last column of the row.
- The asyncPB parameter is a pointer to the asynchronous parameter block. If you
- do not want to call the function asynchronously, set this parameter to NIL.
-
- Result codes
- noErr 0 No error; no next data item
- rcDBNull –800 The data item was NULL
- rcDBValue –801 A nonzero data item was successfully retrieved
- rcDBError –802 Execution ended in an error
- rcDBBadType –803 Next data item not of requested data type
- rcDBBreak –805 Timed out
- rcDBBadSessID –807 Session ID is invalid
- rcDBAsyncNotSupp –811 Asynchronous calls are not supported by
- database extension
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- FUNCTION DBUnGetItem (sessID: LongInt; asyncPB: DBAsyncParmBlkPtr) : OSErr;
-
- The DBUnGetItem function reverses the effect of the last call to the DBGetItem
- function, in the sense that the next time you call the DBGetItem function it
- retrieves the same item a second time. It does not remove the just-retrieved
- data item from the input buffer. The DBUnGetItem function can reverse the effect
- of only one call to the DBGetItem function; you cannot use it to step back
- through several previously retrieved data items.
-
- The sessID parameter is the session ID that was returned by the DBInit function.
-
- The asyncPB parameter is a pointer to the asynchronous parameter block. If you
- do not want to call the function asynchronously, set this parameter to NIL.
-
- Result codes
- noErr 0 No error
- rcDBError –802 Error executing function
- rcDBBadSessID –807 Session ID is invalid
- rcDBAsyncNotSupp –811 Asynchronous calls are not supported by
- database extension
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- _______________________________________________________________________________
-
- æKY Installing…and…Removing…Result…Handlers
- æC »Installing and Removing Result Handlers Database Access Manager
- _______________________________________________________________________________
-
- The functions in this section install, remove, and return pointers to result
- handlers. Result handlers are discussed in “Converting Query Results to Text”
- earlier in this chapter.
-
- FUNCTION DBInstallResultHandler (dataType: DBType; theHandler: ProcPtr;
- isSysHandler: Boolean) : OSErr;
-
- The DBInstallResultHandler function installs a result handler for the data type
- specified by the dataType parameter. The result handler is then used by the
- DBResultsToText function to convert data of the specified type into a character
- string.
-
- The parameter theHandler is a pointer to the result handler. The isSysHandler
- parameter specifies whether the result handler is an application result
- handler—to be used only when the DBResultsToText function is called by the
- application that installed the result handler—or a system result handler—to be
- used by every application running on the system.
-
- When you install an application result handler, it replaces any result handler
- with the same name previously installed by that application. Similarly, when you
- install a system result handler, it replaces any existing system result handler
- with the same name. Before you temporarily replace an existing result handler,
- use the DBGetResultHandler function to obtain a pointer to the present handler,
- and save the present result handler in your application’s private storage. Then
- you can reinstall the original result handler when you are finished using the
- temporary one.
-
- Because an application result handler is used in preference to a system result
- handler if both are available, you can temporarily replace a system result
- handler for purposes of your application by installing an application result
- handler for the same data type. You can then use the DBRemoveResultHandler
- function to remove the application result handler and return to using the system
- result handler whenever you wish.
-
- Result code
- noErr 0 No error
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- FUNCTION DBRemoveResultHandler (dataType: DBType) : OSErr;
-
- The DBRemoveResultHandler function removes from memory the application result
- handler for the data type that you specify with the dataType parameter. This
- function cannot remove a system result handler.
-
- Result codes
- noErr 0 No error
- rcDBNoHandler –813 There is no handler for this data type installed
- for the current application
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- FUNCTION DBGetResultHandler (dataType: DBType; VAR theHandler: ProcPtr;
- isSysHandler: Boolean) : OSErr;
-
- The DBGetResultHandler function returns a pointer to a result handler for the
- data type specified with the dataType parameter. The pointer is returned in the
- parameter theHandler.
-
- If you set the isSysHandler parameter to FALSE (0), the function returns a
- pointer to the current application result handler for the specified data type,
- or it returns 0 if there is no application result handler for that data type. If
- you set the isSysHandler parameter to TRUE (nonzero), the function returns a
- pointer to the current system result handler for the specified data type, or it
- returns 0 if there is no system result handler for that data type.
-
- You can use this function to obtain a pointer to a result handler so that you
- can use it to convert to text an individual data item retrieved by the
- DBGetItem function. The DBGetQueryResults function automatically converts to
- text all of the data pointed to by the results record.
-
- Result codes
- noErr 0 No error
- rcDBNoHandler –813 There is no handler for this data type installed
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
-
- _______________________________________________________________________________
-
- æKY Summary…of…the…Database…Access…Manager
- æC »SUMMARY OF THE DATABASE ACCESS MANAGER Database Access Manager
- _______________________________________________________________________________
-
-
-
- The following cards summarize the data types, constants, and routines for the
- Database Access Manager.
- _______________________________________________________________________________
-
- æKY Database…Access…Manager…Constants
- æC »Constants Database Access Manager
- _______________________________________________________________________________
-
- CONST {Data types}
- typeAnyType = 0; {can be any data type}
- typeNone = 'none'; {no more data expected}
- typeBoolean = 'bool'; {Boolean}
- typeSMInt = 'smin'; {short integer}
- typeInteger = 'int '; {integer}
- typeSMFloat = 'smfl'; {short floating point}
- typeFloat = 'flot'; {floating point}
- typeDate = 'date'; {date}
- typeTime = 'time'; {time}
- typeTimeStamp = 'tims'; {date and time}
- typeChar = 'char'; {character}
- typeDecimal = 'decm'; {decimal number}
- typeMoney = 'mony'; {money value}
- typeVChar = 'vchr'; {variable character}
- typeVBin = 'vbin'; {variable binary}
- typeLChar = 'lchr'; {long character}
- typeLBin = 'lbin'; {long binary}
- typeDiscard = 'disc'; {discard next data item}
- typeUnknown = 'unkn'; {result handler for unknown data type}
- typeColBreak = 'cbrk'; {result handler for column break}
- typeRowBreak = 'rbrk'; {result handler for end of line}
-
- {DBStartQuery status messages}
-
- kDBUpdateWind = 0; {update windows}
- kDBAboutToInit = 1; {about to call DBInit}
- kDBInitComplete = 2; {DBInit has completed}
- kDBSendComplete = 3; {DBSend has completed}
- kDBExecComplete = 4; {DBExec has completed}
- kDBStartQueryComplete = 5; {DBStartQuery is about to complete}
-
- {DBGetQueryResults status messages}
-
- kDBGetItemComplete = 6; {DBGetItem has completed}
- kDBGetItemEndOfRow = 7; {data item received was end of row}
- kDBGetQueryResultsComplete = 8; {DBGetQueryResults has completed}
-
-
- kDBWaitForever = -1; {infinite timeout value for DBGetItem}
-
- kAsyncSupported = $00000001; {asynchronous execution supported}
-
- kDBLastColFlag = $0001; {data item is last column of the row}
- _______________________________________________________________________________
-
- æKY Database…Access…Manager…Data…Types
- æC »Data Types Database Access Manager
- _______________________________________________________________________________
-
- TYPE DBType = OSType; {data type}
-
- DBAsyncParamBlockRec =
- RECORD
- completionProc: ProcPtr; {pointer to completion routine}
- result: OSErr; {result of call}
- userRef: LongInt; {reserved for use by application}
- ddevRef: LongInt; {reserved for use by ddev}
- reserved: LongInt {reserved for use by Database Access Mgr}
- END;
-
- QueryArray = ARRAY[0..255] OF Handle;
- QueryListPtr = ^QueryArray;
- QueryListHandle = ^QueryListPtr;
-
- ResListElem =
- RECORD
- TheType: ResType; {resource type}
- id: Integer {resource ID}
- END;
-
- ResListArray = ARRAY[0..255] OF ResListElem;
- ResListPtr = ^ResListArray;
- ResListHandle = ^ResListPtr;
-
- QueryRecord =
- Record
- version: Integer; {version number}
- id: Integer; {resource ID of 'qrsc'}
- queryProc: Handle; {handle to query def func}
- ddevName: Str63; {database extension name}
- host: Str255; {name of remote computer}
- user: Str255; {name of user}
- password: Str255; {user's password}
- connStr: Str255; {connection string}
- currQuery: Integer; {index to current query}
- numQueries: Integer; {number of queries}
- queryList: QueryListHandle; {handle to array of handles to queries}
- numRes: Integer; {number of resources}
- resList: ResListHandle; {handle to array of resource types and IDs}
- dataHandle: Handle; {handle to memory for query def func}
- refCon: LongInt {reserved for query def func}
- END;
-
- ResultsRecord =
- RECORD
- numRows: Integer; {number of rows of data}
- numCols: Integer; {number of columns per row}
- colTypes: Handle; {handle to array of data types}
- colData: Handle; {handle to data}
- colInfo: Handle {handle to array of DBColInfoRecord records}
- END;
-
- DBColInfoRecord =
- RECORD
- len: Integer; {length of data item}
- places: Integer; {places for decimal and money data items}
- flags: Integer; {flags for data item}
- END;
-
- DDEVParams =
- RECORD
- message: Integer; {routine selector}
- ddevStorage: LongInt; {storage for use by database extension}
- asyncPB: DBAsyncParmBlkPtr; {pointer to asynch parameter block}
- sessID: LongInt; {session ID}
- returnedID: LongInt; {session ID returned}
- version: LongInt; {version number}
- start: LongInt; {session start time}
- host: StringPtr; {name of remote system}
- user: StringPtr; {user name}
- password: StringPtr; {user password}
- connStr: StringPtr; {connection string}
- network: StringPtr; {name of the network}
- buffer: Ptr; {data buffer}
- err1: LongInt; {primary error code returned}
- err2: LongInt; {secondary error code returned}
- item1: StringPtr; {pointer to object of error message}
- item2: StringPtr; {pointer to object of error message}
- errorMsg: StringPtr; {pointer to error message}
- timeout: LongInt; {timeout value for DBGetItem}
- dataType: DBType; {data type}
- sessNum: Integer; {session number}
- state: Integer; {status of the database server}
- len: Integer; {length of data}
- places: Integer; {decimal places in data item}
- flags: Integer; {flags}
- abort: Boolean {flag for DBBreak}
- END;
- _______________________________________________________________________________
-
- æKY Database…Access…Manager…Routines…Summary
- æC »Routines Database Access Manager
- _______________________________________________________________________________
-
- Initializing and Closing the Database Access Manager
-
- FUNCTION InitDBPack : OSErr;
- FUNCTION QuitDBPack : OSErr;
-
- High-Level Interface: Handling Query Documents
-
- FUNCTION DBGetNewQuery (queryID: Integer; VAR query: QueryHandle) : OSErr;
- FUNCTION DBDisposeQuery (query: QueryHandle) : OSErr;
- FUNCTION DBStartQuery (VAR sessID: LongInt; query: QueryHandle; statusProc:
- ProcPtr; asyncPB: DBAsyncParmBlkPtr) : OSErr;
-
- High-Level Interface: Handling Query Results
-
- FUNCTION DBGetQueryResults (sessID: LongInt; VAR results: ResultsRecord;
- timeout: LongInt; statusProc: ProcPtr; asyncPB:
- DBAsyncParmBlkPtr) : OSErr;
- FUNCTION DBResultsToText (results: ResultsRecord; VAR theText: Handle) : OSErr;
-
- Low-Level Interface: Controlling the Session
-
- FUNCTION DBInit (VAR sessID: LongInt; ddevName: Str63; host, user,password,
- connStr: Str255; asyncPB: DBAsyncParmBlkPtr) : OSErr;
- FUNCTION DBEnd (sessID: LongInt; asyncPB: DBAsyncParmBlkPtr) : OSErr;
- FUNCTION DBGetConnInfo (sessID: LongInt; sessNum: Integer; VAR returnedID,
- version: LongInt; VAR ddevName: Str63; VAR host,user,
- network,connStr: Str255; VAR start: LongInt; VAR state:
- OSErr; asyncPB: DBAsyncParmBlkPtr) : OSErr;
- FUNCTION DBGetSessionNum (sessID: LongInt; VAR sessNum: Integer; asyncPB:
- DBAsyncParmBlkPtr) : OSErr;
- FUNCTION DBKill (asyncPB: DBAsyncParmBlkPtr) : OSErr;
-
- Low-Level Interface: Sending and Executing Queries
-
- FUNCTION DBSend (sessID: LongInt; text: Ptr; len: Integer; asyncPB:
- DBAsyncParmBlkPtr) : OSErr;
- FUNCTION DBSendItem (sessID: LongInt; dataType: DBType; len, places,flags:
- Integer; buffer: Ptr; asyncPB: DBAsyncParmBlkPtr) : OSErr;
- FUNCTION DBExec (sessID: LongInt; asyncPB: DBAsyncParmBlkPtr) :
-
- OSErr;
- FUNCTION DBState (sessID: LongInt; asyncPB: DBAsyncParmBlkPtr) :
-
- OSErr;
- FUNCTION DBGetErr (sessID: LongInt; VAR err1,err2: LongInt; VAR item1,item2,
- errorMsg: Str255; asyncPB: DBAsyncParmBlkPtr) : OSErr;
- FUNCTION DBBreak (sessID: LongInt; abort: Boolean; asyncPB: DBAsyncParmBlkPtr)
- : OSErr;
-
- Low-Level Interface: Retrieving Results
-
- FUNCTION DBGetItem (sessID: LongInt; timeout: LongInt; VAR dataType: DBType;
- VAR len,places,flags: Integer; buffer: Ptr; asyncPB:
- DBAsyncParmBlkPtr) : OSErr;
- FUNCTION DBUnGetItem (sessID: LongInt; asyncPB: DBAsyncParmBlkPtr) : OSErr;
-
- Installing and Removing Result Handlers
-
- FUNCTION DBInstallResultHandler (dataType: DBType; theHandler: ProcPtr;
- isSysHandler: Boolean) : OSErr;
- FUNCTION DBRemoveResultHandler (dataType: DBType) : OSErr;
- FUNCTION DBGetResultHandler (dataType: DBType; VAR theHandler: ProcPtr;
- isSysHandler: Boolean) : OSErr;
- _______________________________________________________________________________
-
- æKY Database…Access…Manager…Result…Codes
- æC »Result Codes Database Access Manager
- _______________________________________________________________________________
-
- noErr 0 No error
- userCanceledErr –128 User canceled the query
- rcDBNull –800 The data item was NULL
- rcDBValue –801 Data available or successfully retrieved
- rcDBError –802 Error executing function
- rcDBBadType –803 Next data item not of requested data type
- rcDBBreak –805 Function timed out
- rcDBExec –806 Query currently executing
- rcDBBadSessID –807 Session ID is invalid
- rcDBBadSessNum –808 Invalid session number
- rcDBBadDDev –809 Couldn’t find the specified database extension, or
- error occurred in opening database extension
- rcDBAsyncNotSupp –811 The database extension does not support
- asynchronous calls
- rcDBBadAsynchPB –812 Invalid parameter block specified
- rcDBNoHandler –813 There is no handler for this data type installed
- for the current application
- rcDBWrongVersion –814 Wrong version number
- rcDBPackNotInited –815 The InitDBPack function has not yet been called
- _______________________________________________________________________________
-
- æKY Assembly-Language…Information…for…Database…Access…Manager
- æC »Assembly-Language Information Database Access Manager
- _______________________________________________________________________________
-
- Constants
-
- ;Data types
-
- typeAnyType EQU 0 ;can be any data type
- typeNone EQU 'none' ;no more data expected
- typeBoolean EQU 'bool' ;Boolean
- typeSMInt EQU 'smin' ;short integer
- typeInteger EQU 'int ' ;integer
- typeSMFloat EQU 'smfl' ;short floating point
- typeFloat EQU 'flot' ;floating point
- typeDate EQU 'date' ;date
- typeTime EQU 'time' ;time
- typeTimeStamp EQU 'tims' ;date and time
- typeChar EQU 'char' ;character
- typeDecimal EQU 'decm' ;decimal number
- typeMoney EQU 'mony' ;money value
- typeVChar EQU 'vchr' ;variable character
- typeVBin EQU 'vbin' ;variable binary
- typeLChar EQU 'lchr' ;long character
- typeLBin EQU 'lbin' ;long binary
- typeDiscard EQU 'disc' ;discard next data item
- typeUnknown EQU 'unkn' ;result handler for unknown data type
- typeColBreak EQU 'cbrk' ;result handler for column break
- typeRowBreak EQU 'rbrk' ;result handler for end of line messages for ddev
-
- kDBInit EQU 0 ;DBInit function
- kDBEnd EQU 1 ;DBEnd function
- kDBGetConnInfo EQU 2 ;DBGetConnInfo function
- kDBGetSessionNum EQU 3 ;DBGetSessionNum function
- kDBSend EQU 4 ;DBSend function
- kDBSendItem EQU 5 ;DBSendItem function
- kDBExec EQU 6 ;DBExec function
- kDBState EQU 7 ;DBState function
- kDBGetErr EQU 8 ;DBGetErr function
- kDBBreak EQU 9 ;DBBreak function
- kDBGetItem EQU 10 ;DBGetItem function
- kDBUnGetItem EQU 11 ;DBUnGetItem function
- kDBKill EQU 12 ;DBKill function
- kDBOpen EQU 100 ;DBOpen function
- kDBClose EQU 101 ;DBClose function
- kDBIdle EQU 102 ;DBIdle function
-
- ;DBStartQuery status messages
-
- kDBUpdateWind EQU 0 ;update windows
- kDBAboutToInit EQU 1 ;about to call DBInit
- kDBInitComplete EQU 2 ;DBInit has completed
- kDBSendComplete EQU 3 ;DBSend has completed
- kDBExecComplete EQU 4 ;DBExec has completed
-
- ;DBGetQueryResults status messages
-
- kDBGetItemComplete EQU 6 ;DBGetItem has completed
- kDBGetItemEndOfRow EQU 7 ;data item received was end of row
- kDBGetQueryResultsComplete EQU 8 ;DBGetQueryResults has completed
-
- ;Miscellaneous
-
- kDBWaitForever EQU -1 ;infinite timeout value for DBGetItem
- kDDEVName EQU 128 ;ID of 'STR ' resource with ddev name
- kDDEVID EQU 128 ;ID of 'ddev' resource
- kDDEVFlags EQU 128 ;ID of 'dflg' resource
- kAsyncSupported EQU 1 ;asynchronous execution supported
- kDBLastColFlag EQU 1 ;data item is last column of the row
-
- Asynchronous Parameter Block Data Structure
-
- completionProc long pointer to completion routine
- result word result of call
- userRef long for application’s use
- ddevRef long for ddev’s use
- reserved long for internal use
-
- Data Structure for Resource List in Query Record
-
- theType long resource type
- id word resource ID
-
- Query Record Data Structure
-
- version word version
- id word ID of 'qrsc' this came from
- queryProc long handle to query def proc
- ddevName 64 bytes ddev name
- host 256 bytes host
- user 256 bytes user
- password 256 bytes other connection info
- currQuery word current query
- numQueries word number of queries in query list
- queryList long handle to list of queries
- numRes word number of resources in resource list
- resList long handle to list of other resources
- dataHandle long data used by query def proc
- refCon long query’s reference value
-
- Results Record Data Structure
-
- numRows word number of rows in result
- numCols word number of columns per row
- colTypes long data type array
- colData long actual results
- colLens long length array
-
- Trap Macros Requiring Routine Selectors
-
- _Pack13
-
- Selector Routine
- $0100 InitDBPack
- $0002 QuitDBPack
- $0E04 DBInit
- $0406 DBEnd
- $1708 DBGetConnInfo
- $050A DBGetSessionNum
- $070C DBSend
- $0B0E DBSendItem
- $0410 DBExec
- $0412 DBState
- $0E14 DBGetErr
- $0516 DBBreak
- $1018 DBGetItem
- $041A DBUnGetItem
- $021C DBKill
- $031E DBGetNewQuery
- $0220 DBDisposeQuery
- $0822 DBStartQuery
- $0824 DBGetQueryResults
- $0426 DBResultsToText
- $0528 DBInstallResultHandler
- $022A DBRemoveResultHandler
- $052C DBGetResultHandler
-
- _______________________________________________________________________________
-
-
- æKY DeferredTaskManager
- æC
-
- THE DEFERRED TASK MANAGER
- _______________________________________________________________________________
-
- About…The…DeferredTaskManager…Chapter
- About…the…Deferred…Task…Manager
- Deferred…Task…Manager…Routine
- Summary…of…the…Deferred…Task…Manager
- _______________________________________________________________________________
-
-
-
- æKY About…The…DeferredTaskManager…Chapter
- æC »ABOUT THIS CHAPTER DeferredTaskManager
- _______________________________________________________________________________
-
- This chapter describes the Deferred Task Manager, which provides improved interrupt
- handling by allowing lengthy tasks to be deferred.
-
- Reader’s guide: Lengthy tasks are usually initiated by slot cards. Hence you
- normally need the information in this chapter only if your
- program deals with slot card interrupts.
-
- _______________________________________________________________________________
-
-
- æKY About…the…Deferred…Task…Manager
- æC »ABOUT THE DEFERRED TASK MANAGER DeferredTaskManager
- _______________________________________________________________________________
-
- The Deferred Task Manager provides a way to defer the execution of interrupt tasks
- until interrupts have been reenabled (processor priority level 0). It maintains a
- deferred task queue; instead of performing a task immediately, you can place the
- information describing the task into the queue by calling the DTInstall procedure.
- All system interrupt handlers check this queue just before returning. If there are
- tasks in the queue and interrupts are about to be reenabled, the tasks are removed
- and then executed with all interrupts enabled.
-
- While useful for all types of interrupt tasks, the Deferred Task Manager is especially
- handy for slot interrupts. Interrupts from NuBus slot devices are received and
- decoded by the VIA2, a second Versatile Interface Adapter
- (Rockwell 6522) chip on the Macintosh II. The VIA2 generates level-2 interrupts and,
- due to the way the VIA chip works, interrupts must be serviced before the processor
- priority level can be lowered (otherwise, a system error will occur). During this
- period (which could be quite long depending on the slot device) other level-2 interrupts
- such as those for sound, as well as all level-1 interrupts, are blocked. By using
- the Deferred Task Manager, the processing of slot interrupts can be deferred until
- all the slots are scanned; just before returning, the slot interrupt handler dispatches
- to any tasks in the deferred task queue.
-
- The deferred task queue is a standard Macintosh Operating System queue, as described
- in the Operating System Utilities chapter. Each entry in the deferred task queue has
- the following structure:
-
- TYPE DeferredTask = RECORD
- qLink: QElemPtr; {next queue entry}
- qType: INTEGER; {queue type}
- dtFlags: INTEGER; {reserved}
- dtAddr: ProcPtr; {pointer to task}
- dtParm: LONGINT; {optional parameter}
- dtReserved: LONGINT {reserved--should be 0}
- END;
-
- QLink points to the next entry in the queue, and qType indicates the queue type,
- which must always be ORD(dtQType).
-
- DTAddr contains a pointer to the task. DTParm is useful only from assembly language.
-
- Assembly-language note: DTParm lets you pass an optional parameter
- to be loaded into register A1 just before
- the task is executed.
-
- _______________________________________________________________________________
-
-
- æKY Deferred…Task…Manager…Routine
- æC »DEFERRED TASK MANAGER ROUTINES DeferredTaskManager
- _______________________________________________________________________________
-
- FUNCTION DTInstall (dtTaskPtr: QElemPtr) : OSErr;
-
- Trap macro _DTInstall
- On entry A0: dtTaskPtr (pointer)
- On exit D0: result code (word)
-
- Note: To reduce overhead at interrupt time, instead of executing
- the _DTInstall trap you can load the jump vector jDTInstall
- into an address register other than A0 and execute a JSR
- instruction using that register.
-
- DTInstall adds the specified task to the deferred task queue. Your application must
- fill in all fields of the task except qLink. DTInstall returns one of the result
- codes listed below.
-
- Result codes noErr No error
- vTypErr Invalid queue element
-
- _______________________________________________________________________________
-
-
- æKY Summary…of…the…Deferred…Task…Manager
- æC »SUMMARY OF THE DEFERRED TASK MANAGER DeferredTaskManager
- _______________________________________________________________________________
-
- Data Types
-
- TYPE
- DeferredTask = RECORD
- qLink: QElemPtr; {next queue entry}
- qType: INTEGER; {queue type}
- dtFlags: INTEGER; {reserved}
- dtAddr: ProcPtr; {pointer to task}
- dtParm: LONGINT; {optional parameter}
- dtReserved: LONGINT {reserved--should be 0}
- END;
-
- _______________________________________________________________________________
-
- Routines
-
- FUNCTION DTInstall (dtTaskPtr: QElemPtr) : OSErr;
-
- _______________________________________________________________________________
-
- Assembly-Language Information
-
- Routines
-
- Trap macro On entry On exit
-
- _DTInstall A0: dtTaskPtr (ptr) D0: result code (word)
-
- Structure of Deferred Task Manager Queue Entry
-
- qLink Pointer to next queue entry
- qType Queue type (word)
- dtFlags Reserved (word)
- dtAddr Address of task
- dtParm Optional parameter (long)
- dtResrvd Reserved—should be 0 (long)
- dtQElSize Size in bytes of queue element
-
- Variables
-
- DTQueue Deferred task queue header (10 bytes)
- JDTInstall Jump vector for DTInstall routine
-
-
- æKY DeskManager
- æC
-
- THE DESK MANAGER
- _______________________________________________________________________________
-
- About…The…DeskManager…Chapter
- About…the…Desk…Manager
- Using…the…Desk…Manager
- Desk…Manager…Routines
- Writing…Your…Own…Desk…Accessories
- Summary…of…the…Desk…Manager
- _______________________________________________________________________________
-
-
-
- æKY About…The…DeskManager…Chapter
- æC »ABOUT THIS CHAPTER DeskManager
- _______________________________________________________________________________
-
- This chapter describes the Desk Manager, the part of the Toolbox that supports the
- use of desk accessories from an application; the Calculator, for example, is a standard
- desk accessory available to any application. You’ll learn how to use the Desk Manager
- routines and how to write your own accessories.
-
- You should already be familiar with:
- • the basic concepts behind the Resource Manager and QuickDraw
- • the Toolbox Event Manager, the Window Manager, the Menu Manager,
- and the Dialog Manager
- • device drivers, as discussed in the Device Manager chapter, if
- you want to write your own desk accessories
-
- _______________________________________________________________________________
-
-
- æKY About…the…Desk…Manager
- æC »ABOUT THE DESK MANAGER DeskManager
- _______________________________________________________________________________
-
- The Desk Manager enables your application to support desk accessories, which are
- “mini-applications” that can be run at the same time as a Macintosh application.
- There are a number of standard desk accessories, such as the Calculator shown in
- Figure 1. You can also write your own desk accessories if you wish.
-
- •••Refer to Figure 1.•••
-
- Figure 1–The Calculator Desk Accessory
-
- The Macintosh user opens desk accessories by choosing them from the standard Apple
- menu (whose title is an apple symbol), which by convention is the first menu in the
- menu bar. When a desk accessory is chosen from this menu, it’s usually displayed in a
- window on the desktop, and that window becomes the active window (see Figure 2).
-
- •••Refer to Figure 2.•••
-
- Figure 2–Opening a Desk Accessory
-
- After being opened, the accessory may be used as long as it’s active. The user can
- activate other windows and then reactivate the desk accessory by clicking inside it.
- Whenever a standard desk accessory is active, it has a close box in its title bar.
- Clicking the close box (or choosing Close from the File menu) makes the accessory
- disappear, and the window that’s then frontmost becomes active.
-
- •••Refer to Technical Note #5:•••
-
- The window associated with a desk accessory is usually a rounded-corner window
- (as shown in Figure 1) or a standard document window, although it can be any type of
- window. It may even look and behave like a dialog window; the accessory can call on
- the Dialog Manager to create the window and then use Dialog Manager routines to
- operate on it. In any case, the window will be a system window, as indicated by the
- fact that its windowKind field contains a negative value.
-
- The Desk Manager provides a mechanism that lets standard commands chosen from the
- Edit menu be applied to a desk accessory when it’s active. Even if the commands
- aren’t particularly useful for editing within the accessory, they may be useful for
- cutting and pasting between the accessory and the application or even another accessory.
- For example, the result of a calculation made with the Calculator can be copied and
- pasted into a document prepared in MacWrite.
-
- A desk accessory may also have its own menu. When the accessory becomes active, the
- title of its menu is added to the menu bar and menu items may be chosen from it. Any
- of the application’s menus or menu items that no longer apply are disabled. A desk
- accessory can even have an entire menu bar full of its own menus, which will completely
- replace the menus already in the menu bar. When an accessory that has its own menu or
- menus becomes inactive, the menu bar is restored to normal.
-
- Although desk accessories are usually displayed in windows (one per accessory); it’s
- possible for an accessory to have only a menu (or menus) and not a window. In this
- case, the menu includes a command to close the accessory. Also, a desk accessory
- that’s displayed in a window may create any number of additional windows while it’s
- open.
-
- A desk accessory is actually a special type of device driver—special in that it may
- have its own windows and menus for interacting with the user. The value in the windowKind
- field of a desk accessory’s window is a reference number that uniquely identifies the
- driver, returned by the Device Manager when the driver was opened. Desk accessories
- and other RAM drivers used by Macintosh applications are stored in resource files.
-
- _______________________________________________________________________________
-
-
- æKY Using…the…Desk…Manager
- æC »USING THE DESK MANAGER DeskManager
- _______________________________________________________________________________
-
- To allow access to desk accessories, your application must do the following:
-
- • Initialize TextEdit and the Dialog Manager, in case any desk
- accessories are displayed in windows created by the Dialog Manager
- (which uses TextEdit).
- • Set up the Apple menu as the first menu in the menu bar. You can put
- the names of all currently available desk accessories in a menu by
- using the Menu Manager procedure AddResMenu.
- • Set up an Edit menu that includes the standard commands Undo, Cut,
- Copy, Paste, and Clear (in that order, with a dividing line between
- Undo and Cut), even if your application itself doesn’t support any
- of these commands.
-
- Note: Applications should leave enough space in the menu bar for a
- desk accessory’s menu to be added.
-
- When the user chooses a desk accessory from the Apple menu, call the Menu Manager
- procedure GetItem to get the name of the desk accessory, and then the Desk Manager
- function OpenDeskAcc to open and display the accessory. When a system window is
- active and the user chooses Close from the File menu, close the desk accessory with
- the CloseDeskAcc procedure.
-
- Warning: Most open desk accessories allocate nonrelocatable objects
- (such as windows) in the heap, resulting in fragmentation of
- heap space. Before beginning an operation that requires a large
- amount of memory, your application may want to close all open
- desk accessories (or allow the user to close some of them).
-
- When the Toolbox Event Manager function GetNextEvent reports that a mouse-down event
- has occurred, your application should call the Window Manager function FindWindow to
- find out where the mouse button was pressed. If FindWindow returns the predefined
- constant inSysWindow, which means that the mouse button was pressed in a system
- window, call the Desk Manager procedure SystemClick. SystemClick handles mouse-down
- events in system windows, routing them to desk accessories where appropriate.
-
- Note: The application needn’t be concerned with exactly which desk
- accessories are currently open.
-
- When the active window changes from an application window to a system window, the
- application should disable any of its menus or menu items that don’t apply while an
- accessory is active, and it should enable the standard editing commands Undo, Cut,
- Copy, Paste, and Clear, in the Edit menu. An application should disable any editing
- commands it doesn’t support when one of its own windows becomes active.
-
- When a mouse-down event occurs in the menu bar, and the application determines that
- one of the five standard editing commands has been invoked, it should call SystemEdit.
- Only if SystemEdit returns FALSE should the application process the editing command
- itself; if the active window belongs to a desk accessory, SystemEdit passes the
- editing command on to that accessory and returns TRUE.
-
- Keyboard equivalents of the standard editing commands are passed on to desk accessories
- by the Desk Manager, not by your application.
-
- Warning: The standard keyboard equivalents for the commands in the Edit
- menu must not be changed or assigned to other commands; the Desk
- Manager automatically interprets Command-Z, X, C, and V as Undo,
- Cut, Copy, and Paste, respectively.
-
- Certain periodic actions may be defined for desk accessories. To see that
- they’re performed, you need to call the SystemTask procedure at least once every time
- through your main event loop.
-
- The two remaining Desk Manager routines—SystemEvent and SystemMenu—are never called
- by the application, but are described in this chapter because they reveal inner
- mechanisms of the Toolbox that may be of interest to advanced programmers.
-
- _______________________________________________________________________________
-
-
- æKY Desk…Manager…Routines
- æC »DESK MANAGER ROUTINES DeskManager
- _______________________________________________________________________________
-
- »Opening and Closing Desk Accessories
-
- FUNCTION OpenDeskAcc (theAcc: Str255) : INTEGER;
-
- OpenDeskAcc opens the desk accessory having the given name and displays its window
- (if any) as the active window. The name is the accessory’s resource name, which you
- get from the Apple menu by calling the Menu Manager procedure GetItem. OpenDeskAcc
- calls the Resource Manager to read the desk accessory from the resource file into the
- application heap.
-
- You should ignore the value returned by OpenDeskAcc. If the desk accessory is successfully
- opened, the function result is its driver reference number. However, if the desk
- accessory can’t be opened, the function result is undefined; the accessory will have
- taken care of informing the user of the problem (such as memory full) and won’t
- display itself.
-
- Warning: Early versions of some desk accessories may set the current
- grafPort to the accessory’s port upon return from OpenDeskAcc.
- To be safe, you should bracket your call to OpenDeskAcc with
- calls to the QuickDraw procedures GetPort and SetPort, to save
- and restore the current port.
-
- Note: Programmers concerned about the amount of available memory should
- be aware that an open desk accessory uses from 1K to 3K bytes of
- heap space in addition to the space needed for the accessory itself.
- The desk accessory is responsible for determining whether there is
- sufficient memory for it to run; this can be done by calling
- SizeResource followed by ResrvMem.
-
- PROCEDURE CloseDeskAcc (refNum: INTEGER);
-
- When a system window is active and the user chooses Close from the File menu, call
- CloseDeskAcc to close the desk accessory. RefNum is the driver reference number for
- the desk accessory, which you get from the windowKind field of its window.
-
- The Desk Manager automatically closes a desk accessory if the user clicks its close
- box. Also, since the application heap is released when the application terminates,
- every desk accessory goes away at that time.
-
- _______________________________________________________________________________
-
- »Handling Events in Desk Accessories
-
- PROCEDURE SystemClick (theEvent: EventRecord; theWindow: WindowPtr);
-
- When a mouse-down event occurs and the Window Manager function FindWindow reports
- that the mouse button was pressed in a system window, the application should call
- SystemClick with the event record and the window pointer. If the given window belongs
- to a desk accessory, SystemClick sees that the event gets handled properly.
-
- SystemClick determines which part of the desk accessory’s window the mouse button was
- pressed in, and responds accordingly (similar to the way your application responds to
- mouse activities in its own windows).
-
- • If the mouse button was pressed in the content region of the window
- and the window was active, SystemClick sends the mouse-down event to
- the desk accessory, which processes it as appropriate.
- • If the mouse button was pressed in the content region and the window
- was inactive, SystemClick makes it the active window.
- • If the mouse button was pressed in the drag region, SystemClick calls
- the Window Manager procedure DragWindow to pull an outline of the window
- across the screen and move the window to a new location. If the window
- was inactive, DragWindow also makes it the active window (unless the
- Command key was pressed along with the mouse button).
- • If the mouse button was pressed in the go-away region, SystemClick calls
- the Window Manager function TrackGoAway to determine whether the mouse
- is still inside the go-away region when the click is completed: If
- so, it tells the desk accessory to close itself; otherwise, it does
- nothing.
-
- FUNCTION SystemEdit (editCmd: INTEGER) : BOOLEAN;
-
- Assembly-language note: The macro you invoke to call SystemEdit from
- assembly language is named _SysEdit.
-
- Call SystemEdit when there’s a mouse-down event in the menu bar and the user chooses
- one of the five standard editing commands from the Edit menu. Pass one of the following
- as the value of the editCmd parameter:
-
- editCmd Editing command
-
- 0 Undo
- 2 Cut
- 3 Copy
- 4 Paste
- 5 Clear
-
- If your Edit menu contains these five commands in the standard arrangement (the order
- listed above, with a dividing line between Undo and Cut), you can simply call
-
- SystemEdit(menuItem-1)
-
- where menuItem is the menu item number.
-
- If the active window doesn’t belong to a desk accessory, SystemEdit returns FALSE;
- the application should then process the editing command as usual. If the active
- window does belong to a desk accessory, SystemEdit asks that accessory to process the
- command and returns TRUE; in this case, the application should ignore the command.
-
- Note: It’s up to the application to make sure desk accessories get
- their editing commands that are chosen from the Edit menu. In
- particular, make sure your application hasn’t disabled the Edit
- menu or any of the five standard commands when a desk accessory
- is activated.
-
- _______________________________________________________________________________
-
- »Performing Periodic Actions
-
- PROCEDURE SystemTask;
-
- For each open desk accessory (or other device driver performing periodic actions),
- SystemTask causes the accessory to perform the periodic action defined for it, if any
- such action has been defined and if the proper time period has passed since the
- action was last performed. For example, a clock accessory can be defined such that
- the second hand is to move once every second; the periodic action for the accessory
- will be to move the second hand to the next position, and SystemTask will alert the
- accessory every second to perform that action.
-
- You should call SystemTask as often as possible, usually once every time through your
- main event loop. Call it more than once if your application does an unusually large
- amount of processing each time through the loop.
-
- Note: SystemTask should be called at least every sixtieth of a second.
-
- _______________________________________________________________________________
-
- »Advanced Routines
-
- FUNCTION SystemEvent (theEvent: EventRecord) : BOOLEAN;
-
- SystemEvent is called only by the Toolbox Event Manager function GetNextEvent when it
- receives an event, to determine whether the event should be handled by the application
- or by the system. If the given event should be handled by the application, SystemEvent
- returns FALSE; otherwise, it calls the appropriate system code to handle the event
- and returns TRUE.
-
- In the case of a null or mouse-down event, SystemEvent does nothing but return FALSE.
- Notice that it responds this way to a mouse-down event even though the event may in
- fact have occurred in a system window (and therefore may have to be handled by the
- system). The reason for this is that the check for exactly where the event occurred
- (via the Window Manager function FindWindow) is made later by the application and so
- would be made twice if SystemEvent were also to do it. To avoid this duplication,
- SystemEvent passes the event on to the application and lets it make the sole call to
- FindWindow. Should FindWindow reveal that the mouse-down event did occur in a system
- window, the application can then call SystemClick, as described above, to get the
- system to handle it.
-
- If the given event is a mouse-up or any keyboard event (including keyboard equivalents
- of commands), SystemEvent checks whether the active window belongs to a desk accessory
- and whether that accessory can handle this type of event. If so, it sends the event
- to the desk accessory and returns TRUE; otherwise, it returns FALSE.
-
- If SystemEvent is passed an activate or update event, it checks whether the window
- the event occurred in is a system window belonging to a desk accessory and whether
- that accessory can handle this type of event. If so, it sends the event to the desk
- accessory and returns TRUE; otherwise, it returns FALSE.
-
- Note: It’s unlikely that a desk accessory would not be set up to handle
- keyboard, activate, and update events, or that it would handle
- mouse-up events.
-
- If the given event is a disk-inserted event, SystemEvent does some
- low-level processing (by calling the File Manager function MountVol)
- but passes the event on to the application by returning FALSE, in
- case the application wants to do further processing. Finally,
- SystemEvent returns FALSE for network, device driver, and
- application-defined events.
-
- Assembly-language note: Advanced programmers can make SystemEvent
- always return FALSE by setting the global
- variable SEvtEnb (a byte) to 0.
-
- PROCEDURE SystemMenu (menuResult: LONGINT);
-
- SystemMenu is called only by the Menu Manager functions MenuSelect and MenuKey, when
- an item in a menu belonging to a desk accessory has been chosen. The menuResult
- parameter has the same format as the value returned by MenuSelect and MenuKey: the
- menu ID in the high-order word and the menu item number in the low-order word. (The
- menu ID will be negative.) SystemMenu directs the desk accessory to perform the
- appropriate action for the given menu item.
-
- _______________________________________________________________________________
-
-
- æKY Writing…Your…Own…Desk…Accessories
- æC »WRITING YOUR OWN DESK ACCESSORIES DeskManager
- _______________________________________________________________________________
-
- To write your own desk accessory, you must create it as a device driver and include
- it in a resource file, as described in the Device Manager chapter. Standard or shared
- desk accessories are stored in the system resource file. Accessories specific to an
- application are rare; if there are any, they’re stored in the application’s resource
- file.
-
- The resource type for a device driver is 'DRVR'. The resource ID for a desk accessory
- is the driver’s unit number and must be between 12 and 31 inclusive.
-
- Note: A desk accessory will often have additional resources (such as
- pattern and string resources) that are associated with it. These
- resources must observe a special numbering convention, as described
- in the Resource Manager chapter.
-
- The resource name should be whatever you want to appear in the Apple menu, but should
- also include a nonprinting character; by convention, the name should begin with a NUL
- character (ASCII code 0). The nonprinting character is needed to avoid conflict with
- file names that are the same as the names of desk accessories.
-
- Device drivers are usually written in assembly language. The structure of a device
- driver is described in the Device Manager chapter. The rest of this section reviews
- some of that information and presents additional details pertaining specifically to
- device drivers that are desk accessories.
-
- As shown in Figure 3, a device driver begins with a few words of flags and other
- data, followed by offsets to the routines that do the work of the driver, an optional
- title, and finally the routines themselves.
-
- •••Refer to Figure 3.•••
-
- Figure 3–Desk Accessory Device Driver
-
- One bit in the high-order byte of the drvrFlags word is frequently used by desk
- accessories:
-
- dNeedTime .EQU 5 ; set if driver needs time for performing
- ; a periodic action
-
- Desk accessories may need to perform predefined actions periodically. For example, a
- clock desk accessory may want to change the time it displays every second. If the
- dNeedTime flag is set, the desk accessory does need to perform a periodic action, and
- the drvrDelay word contains a tick count indicating how often the periodic action
- should occur. Whether the action actually occurs as frequently as specified depends
- on how often the application calls the Desk Manager procedure SystemTask. SystemTask
- calls the desk accessory’s control routine (if the time indicated by drvrDelay has
- elapsed), and the control routine must perform whatever predefined action is desired.
-
- Note: A desk accessory cannot rely on SystemTask being called regularly
- or frequently by an application. If it needs precise timing it
- should install a task to be executed during the vertical retrace
- interrupt. There are, however, certain restrictions on tasks
- performed during interrupts, such as not being able to make calls
- to the Memory Manager. For more information on these restrictions,
- see the Vertical Retrace Manager chapter. Periodic actions performed
- in response to SystemTask calls are not performed via an interrupt
- and so don’t have these restrictions.
-
- The drvrEMask word contains an event mask specifying which events the desk accessory
- can handle. If the accessory has a window, the mask should include keyboard, activate,
- update, and mouse-down events, but must not include mouse-up events.
-
- Note: The accessory may not be interested in keyboard input, but it
- should still respond to key-down and auto-key events, at least
- with a beep.
-
- When an event occurs, the Toolbox Event Manager calls SystemEvent. SystemEvent checks
- the drvrEMask word to determine whether the desk accessory can handle the type of
- event, and if so, calls the desk accessory’s control routine. The control routine
- must perform whatever action is desired.
-
- If the desk accessory has its own menu (or menus), the drvrMenu word contains the
- menu ID of the menu (or of any one of the menus); otherwise, it contains 0. The menu
- ID for a desk accessory menu must be negative, and it must be different from the menu
- ID stored in other desk accessories.
-
- Following these four words are the offsets to the driver routines and, optionally, a
- title for the desk accessory (preceded by its length in bytes). You can use the title
- in the driver as the title of the accessory’s window, or just as a way of identifying
- the driver in memory.
-
- Note: A practical size limit for desk accessories is about 8K bytes.
-
- _______________________________________________________________________________
-
- »The Driver Routines
-
- Of the five possible driver routines, only three need to exist for desk accessories: the
- open, close, and control routines. The other routines (prime and status) may be used
- if desired for a particular accessory.
- The open routine opens the desk accessory:
-
- • It creates the window to be displayed when the accessory is opened,
- if any, specifying that it be invisible (since OpenDeskAcc will
- display it). The window can be created with the Dialog Manager
- function GetNewDialog (or NewDialog) if desired; the accessory
- will look and respond like a dialog box, and subsequent operations
- may be performed on it with Dialog Manager routines. In any case,
- the open routine sets the windowKind field of the window record to
- the driver reference number for the desk accessory, which it gets
- from the device control entry. (The reference number will be negative.)
- It also stores the window pointer in the device control entry.
- • If the driver has any private storage, it allocates the storage,
- stores a handle to it in the device control entry, and initializes
- any local variables. It might, for example, create a menu or menus
- for the accessory.
-
- If the open routine is unable to complete all of the above tasks (if it runs out of
- memory, for example), it must do the following:
-
- • Open only the minimum of data structures needed to run the desk accessory.
- • Modify the code of every routine (except the close routine) so that
- the routine just returns (or beeps) when called.
- • Modify the code of the close routine so that it disposes of only the
- minimum data structures that were opened.
- • Display an alert indicating failure, such as “The Note Pad is not
- available”.
-
- The close routine closes the desk accessory, disposing of its window (if any) and all
- the data structures associated with it and replacing the window pointer in the device
- control entry with NIL. If the driver has any private storage, the close routine also
- disposes of that storage.
-
- Warning: A driver’s private storage shouldn’t be in the system heap,
- because the application heap is reinitialized when an application
- terminates, and the driver is lost before it can dispose of its
- storage.
-
- The action taken by the control routine depends on information passed in the parameter
- block pointed to by register A0. A message is passed in the csCode parameter; this
- message is simply a number that tells the routine what action to take. There are nine
- such messages:
-
- accEvent .EQU 64 ;handle a given event
- accRun .EQU 65 ;take the periodic action, if any,
- ; for this desk accessory
- accCursor .EQU 66 ;change cursor shape if appropriate; generate
- ; null event if window was created by Dialog Manager
- accMenu .EQU 67 ;handle a given menu item
- accUndo .EQU 68 ;handle the Undo command
- accCut .EQU 70 ;handle the Cut command
- accCopy .EQU 71 ;handle the Copy command
- accPaste .EQU 72 ;handle the Paste command
- accClear .EQU 73 ;handle the Clear command
-
- Note: As described in the Device Manager chapter, the control routine
- may also receive the message goodBye in the csCode parameter telling
- it when the heap is about to be reinitialized.
-
- Along with the accEvent message, the control routine receives in the csParam field a
- pointer to an event record. The control routine must respond by handling the given
- event in whatever way is appropriate for this desk accessory. SystemClick and SystemEvent
- call the control routine with this message to send the driver an event that it should
- handle—for example, an activate event that makes the desk accessory active or inactive.
- When a desk accessory becomes active, its control routine might install a menu in the
- menu bar. If the accessory becoming active has more than one menu, the control routine
- should respond as follows:
-
- • Store the accessory’s unique menu ID in the global variable
- MBarEnable. (This is the negative menu ID in the device driver
- and the device control entry.)
- • Call the Menu Manager routines GetMenuBar to save the current
- menu list and ClearMenuBar to clear the menu bar.
- • Install the accessory’s own menus in the menu bar.
-
- Then, when the desk accessory becomes inactive, the control routine should call
- SetMenuBar to restore the former menu list, call DrawMenuBar to draw the menu bar,
- and set MBarEnable to 0.
-
- The accRun message tells the control routine to perform the periodic action for this
- desk accessory. For every open driver that has the dNeedTime flag set, the SystemTask
- procedure calls the control routine with this message if the proper time period has
- passed since the action was last performed.
-
- The accCursor message makes it possible to change the shape of the cursor when it’s
- inside an active desk accessory. SystemTask calls the control routine with this
- message as long as the desk accessory is active. The control routine should respond
- by checking whether the mouse location is in the desk
- accessory’s window; if it is, it should set it to the standard arrow cursor (by
- calling the QuickDraw procedure InitCursor), just in case the application has changed
- the cursor and failed to reset it. Or, if desired, your accessory may give the cursor
- a special shape (by calling the QuickDraw procedure SetCursor).
-
- If the desk accessory is displayed in a window created by the Dialog Manager, the
- control routine should respond to the accCursor message by generating a null event
- (storing the event code for a null event in an event record) and passing it to DialogSelect.
- This enables the Dialog Manager to blink the caret in editText items. In assembly
- language, the code might look like this:
-
- CLR.L -(SP) ;event code for null event is 0
- PEA 2(SP) ;pass null event
- CLR.L -(SP) ;pass NIL dialog pointer
- CLR.L -(SP) ;pass NIL pointer
- _DialogSelect ;invoke DialogSelect
- ADDQ.L #4,SP ;pop off result and null event
-
- When the accMenu message is sent to the control routine, the following information is
- passed in the parameter block: csParam contains the menu ID of the desk accessory’s
- menu and csParam+2 contains the menu item number. The control routine should take the
- appropriate action for when the given menu item is chosen from the menu, and then
- make the Menu Manager call HiliteMenu(0) to remove the highlighting from the menu
- bar.
-
- Finally, the control routine should respond to one of the last five messages—accUndo
- through accClear—by processing the corresponding editing command in the desk accessory
- window if appropriate. SystemEdit calls the control routine with these messages. For
- information on cutting and pasting between a desk accessory and the application, or
- between two desk accessories, see the Scrap Manager chapter.
-
- Warning: If the accessory opens a resource file, or otherwise changes
- which file is the current resource file, it should save and
- restore the previous current resource file, using the Resource
- Manager routines CurResFile and UseResFile. Similarly, the
- accessory should save and restore the port that was the current
- grafPort, using the QuickDraw routines GetPort and SetPort.
-
- _______________________________________________________________________________
-
-
- æKY Summary…of…the…Desk…Manager
- æC »SUMMARY OF THE DESK MANAGER DeskManager
- _______________________________________________________________________________
-
- Routines
-
- Opening and Closing Desk Accessories
-
- FUNCTION OpenDeskAcc (theAcc: Str255) : INTEGER;
- PROCEDURE CloseDeskAcc (refNum: INTEGER);
-
- Handling Events in Desk Accessories
-
- PROCEDURE SystemClick (theEvent: EventRecord; theWindow: WindowPtr);
- FUNCTION SystemEdit (editCmd: INTEGER) : BOOLEAN;
-
- Performing Periodic Actions
-
- PROCEDURE SystemTask;
-
- Advanced Routines
-
- FUNCTION SystemEvent (theEvent: EventRecord) : BOOLEAN;
- PROCEDURE SystemMenu (menuResult: LONGINT);
-
- _______________________________________________________________________________
-
- Assembly-Language Information
-
- Constants
-
- ; Desk accessory flag
-
- dNeedTime .EQU 5 ; set if driver needs time for performing
- ; a periodic action
-
- ; Control routine messages
-
- accEvent .EQU 64 ;handle a given event
- accRun .EQU 65 ;take the periodic action, if any,
- ; for this desk accessory
- accCursor .EQU 66 ;change cursor shape if appropriate; generate
- ; null event if window was created by Dialog Manager
- accMenu .EQU 67 ;handle a given menu item
- accUndo .EQU 68 ;handle the Undo command
- accCut .EQU 70 ;handle the Cut command
- accCopy .EQU 71 ;handle the Copy command
- accPaste .EQU 72 ;handle the Paste command
- accClear .EQU 73 ;handle the Clear command
-
- Special Macro Names
-
- Pascal name Macro name
-
- SystemEdit _SysEdit
-
- Variables
-
- MBarEnable Unique menu ID for active desk accessory, when menu bar
- belongs to the accessory (word)
- SEvtEnb 0 if SystemEvent should return FALSE (byte)
-
- Further Reference:
- _______________________________________________________________________________
- Resource Manager
- QuickDraw
- Toolbox Event Manager
- Window Manager
- Menu Manager
- Device Manager
- Technical Note #5, Using Modeless Dialogs from Desk Accessories
- Technical Note #85, GetNextEvent; Blinking Apple Menu
-
- æKY DeviceManager
- æC
-
- THE DEVICE MANAGER
- _______________________________________________________________________________
-
- About…The…DeviceManager…Chapter
- About…the…Device…Manager
- Using…the…Device…Manager
- Device…Manager…Routines
- The…Structure…of…a…Device…Driver
- Writing…Your…Own…Device…Drivers
- Interrupts
- The…Chooser
- The…Startup…Process
- Opening…Slot…Devices
- Slot…Device…Interrupts
- New…Routines
- Summary…of…the…Device…Manager
- _______________________________________________________________________________
-
-
-
- æKY About…The…DeviceManager…Chapter
- æC »ABOUT THIS CHAPTER DeviceManager
- _______________________________________________________________________________
-
- This chapter describes the Device Manager, the part of the Operating System that
- controls the exchange of information between a Macintosh application and devices. It
- gives general information about using and writing device drivers, and also discusses
- interrupts: how the Macintosh uses them and how you can use them if you’re writing
- your own device driver.
-
- Note: Specific information about the standard Macintosh drivers is
- contained in separate chapters.
-
- You should already be familiar with resources, as discussed in the Resource Manager
- section.
-
- _______________________________________________________________________________
-
-
- æKY About…the…Device…Manager
- æC »ABOUT THE DEVICE MANAGER DeviceManager
- _______________________________________________________________________________
-
- Note: The extensions to the Device Manager described in this chapter were
- originally documented in Inside Macintosh, Volumes IV and V. As such,
- the Volume IV information refers to the 128K ROM and System file
- version 3.2 and later, while the Volume V information refers to the
- Macintosh SE and Macintosh II ROMs and System file version 4.1 and
- later. The sections of this chapter that cover these extensions are
- so noted.
-
- The Device Manager is the part of the Operating System that handles communication
- between applications and devices. A device is a part of the Macintosh, or a piece of
- external equipment, that can transfer information into or out of the Macintosh.
- Macintosh devices include disk drives, two serial communications ports, and printers.
-
- Note: The display screen is not a device; drawing on the screen is
- handled by QuickDraw.
-
- There are two kinds of devices: character devices and block devices. A character
- device reads or writes a stream of characters, or bytes, one at a time: It can
- neither skip bytes nor go back to a previous byte. A character device is used to get
- information from or send information to the world outside of the Operating System and
- memory: It can be an input device, an output device, or an input/output device. The
- serial ports and printers are all character devices.
-
- A block device reads and writes blocks of bytes at a time; it can read or write any
- accessible block on demand. Block devices are usually used to store and retrieve
- information; for example, disk drives are block devices.
-
- Applications communicate with devices through the Device Manager—either directly or
- indirectly (through another part of the Operating System or
- Toolbox). For example, an application can communicate with a disk drive directly via
- the Device Manager, or indirectly via the File Manager (which calls the Device Manager).
- The Device Manager doesn’t manipulate devices directly; it calls device drivers that
- do (see Figure 1). Device drivers are programs that take data coming from the Device
- Manager and convert them into actions of devices, or convert device actions into data
- for the Device Manager to process.
-
- The Operating System includes three standard device drivers in ROM: the Disk Driver,
- the Sound Driver, and the ROM Serial Driver. There are also a number of standard RAM
- drivers, including the Printer Driver, the RAM Serial Driver, the AppleTalk drivers,
- and desk accessories. RAM drivers are resources, and are read from the system resource
- file as needed.
-
- You can add other drivers independently or build on top of the existing drivers (for
- example, the Printer Driver is built on top of the Serial Driver); the section “Writing
- Your Own Device Drivers” describes how to do this. Desk accessories are a special
- type of device driver, and are manipulated via the routines of the Desk Manager.
-
- •••Refer to Figure 1.•••
-
- Figure 1–Communication with Devices
-
- Warning: Information about desk accessories covered in the Desk Manager
- chapter is not repeated here. Some information in this chapter
- may not apply to desk accessories.
-
- A device driver can be either open or closed. The Sound Driver and Disk Driver are
- opened when the system starts up; the rest of the drivers are opened at the specific
- request of an application. After a driver has been opened, an application can read
- data from and write data to it. You can close device drivers that are no longer in
- use, and recover the memory used by them. Up to 32 device drivers may be open at any
- one time.
-
- Before it’s opened, you identify a device driver by its driver name; after it’s
- opened, you identify it by its reference number. A driver name consists of a period
- (.) followed by any sequence of 1 to 254 printing characters. A RAM driver’s name is
- the same as its resource name. You can use uppercase and lowercase letters when
- naming drivers, but the Device Manager ignores case when comparing names (it doesn’t
- ignore diacritical marks).
-
- Note: Although device driver names can be quite long, there’s little
- reason for them to be more than a few characters in length.
-
- The Device Manager assigns each open device driver a driver reference number, from –1
- to –32, that’s used instead of its driver name to refer to it.
-
- Most communication between an application and an open device driver occurs by reading
- and writing data. Data read from a driver is placed in the
- application’s data buffer, and data written to a driver is taken from the application’s
- data buffer. A data buffer is memory allocated by the application for communication
- with drivers.
-
- In addition to data that’s read from or written to device drivers, drivers may require
- or provide other information. Information transmitted to a driver by an application
- is called control information; information provided by a driver is called status
- information. Control information may select modes of operation, start or stop processes,
- enable buffers, choose protocols, and so on. Status information may indicate the
- current mode of operation, the readiness of the device, the occurrence of errors, and
- so on. Each device driver may respond to a number of different types of control
- information and may provide a number of different types of status information.
-
- Each of the standard Macintosh drivers includes predefined calls for transmitting
- control information and receiving status information. Explanations of these calls can
- be found in the chapters describing the drivers.
-
- Note: The extensions to the Device Manager described in the following
- paragraphs were originally documented in Inside Macintosh, Volume IV.
- As such, this information refers to the 128K ROMs and System file
- version 3.2 and later.
-
- While no new routines have been added to the Device Manager with the Macintosh Plus,
- the handling of the existing routines has been significantly improved.
-
- When an Open call is made, installed drivers are searched first (before resources) to
- avoid replacing a current driver; this search is done by name so be sure that your
- driver’s name is in the driver header. All drivers, exclusive of desk accessories,
- must have a name that begins with a period; otherwise, the Open call is passed on to
- the File Manager.
-
- If a driver is already open, Open calls will not be sent to the driver’s open routine,
- preserving its device control entry. A desk accessory will, however, receive another
- call (certain desk accessories count on this).
-
- If a driver fails to open because of a resource load problem, the Open call terminates
- with the appropriate error code instead of being passed on to the File Manager (which
- would usually return the result code fnfErr). If a driver returns a negative result
- code in register D0 from an Open call, the result code is passed back and the driver
- is not opened. If a driver returns the result code closeErr in register D0 from a
- Close call, this result code is passed back and the driver is not closed.
-
- Open, Close, Read, Write, Control, and Status return all results in the ioResult
- field as well as in register D0. A KillIO call is passed to the driver only if it’s
- open and enabled for Control calls.
-
- The number of device control entries in the 128K ROM has been increased from 32 to
- 48. The unit table is now a 192-byte nonrelocatable block containing 48
- four-byte entries; the standard unit table assignments are as follows:
-
- Unit Number Device
-
- 0 Reserved
- 1 Hard disk driver: Macintosh XL internal or Hard Disk 20 external
- 2 .Print driver
- 3 .Sound driver
- 4 .Sony driver
- 5 Modem port asynchronous driver input (.AIn)
- 6 Modem port asynchronous driver output (.AOut)
- 7 Printer port asynchronous driver input (.BIn)
- 8 Printer port asynchronous driver output (.BOut)
- 9 AppleTalk .MPP driver
- 10 AppleTalk .ATP driver
- 11 Reserved
- 12–26 Desk accessories in System file
- 27–31 Desk accessories in application files
- 32–39 SCSI drivers 0–7
- 40–47 Reserved
-
- Note: The extensions to the Device Manager described in the following
- paragraphs were originally documented in Inside Macintosh, Volume V.
- As such, this information refers to the Macintosh SE and Macintosh II
- ROMs and System file version 4.1 and later.
-
- New modifications have been made to the Device Manager to support slot devices.
-
- Reader’s guide: You need the information in the slot-related sections of
- this chapter only if your application uses a specific card
- (other than a standard video card) that plugs into a NuBus™
- slot on the Macintosh II.
-
- These slot-related sections cover the following subjects:
-
- • the parts of the system startup procedure that affect slot devices
- • how the Open call now handles slot devices
- • how interrupts originating in slot devices are processed
- • how the new Chooser works with slot devices
-
- You’ll also need to be familiar with
-
- • the Start Manager
- • the Slot Manager
- • the parts of the book “Designing Cards and Drivers for Macintosh
- II and Macintosh SE” that pertain to the device your application uses.
-
- _______________________________________________________________________________
-
-
- æKY Using…the…Device…Manager
- æC »USING THE DEVICE MANAGER DeviceManager
- _______________________________________________________________________________
-
- You can call Device Manager routines via three different methods: high-level Pascal
- calls, low-level Pascal calls, and assembly language. The high-level Pascal calls are
- designed for Pascal programmers interested in using the Device Manager in a simple
- manner; they provide adequate device I/O and don’t require much special knowledge to
- use. The low-level Pascal and assembly-language calls are designed for advanced
- Pascal programmers and assembly-language programmers interested in using the Device
- Manager to its fullest capacity; they require some special knowledge to be used most
- effectively.
-
- Note: The names used to refer to routines here are actually
- assembly-language macro names for the low-level routines,
- but the Pascal routine names are very similar.
-
- The Device Manager is automatically initialized each time the system starts up.
-
- Before an application can exchange information with a device driver, the driver must
- be opened. The Sound Driver and Disk Driver are opened when the system starts up; for
- other drivers, the application must call Open. The Open routine will return the
- driver reference number that you’ll use every time you want to refer to that device
- driver.
-
- An application can send data from its data buffer to an open driver with a Write
- call, and transfer data from an open driver to its data buffer with Read. An application
- passes control information to a device driver by calling Control, and receives status
- information from a driver by calling Status.
-
- Whenever you want to stop a device driver from completing I/O initiated by a Read,
- Write, Control, or Status call, call KillIO. KillIO halts any current I/O and deletes
- any pending I/O.
-
- When you’re through using a driver, call Close. Close forces the device driver to
- complete any pending I/O, and then releases all the memory used by the driver.
-
- _______________________________________________________________________________
-
-
- æKY Device…Manager…Routines
- æC »DEVICE MANAGER ROUTINES DeviceManager
- _______________________________________________________________________________
-
- This section describes the Device Manager routines used to call drivers. It’s divided
- into two parts: The first describes all the high-level Pascal routines of the Device
- Manager, and the second presents information about calling the low-level Pascal and
- assembly-language routines.
-
- All the Device Manager routines in this section return an integer result code of type
- OSErr. Each routine description lists all of the applicable result codes, along with
- a short description of what the result code means. Lengthier explanations of all the
- result codes can be found in the summary at the end of this chapter.
-
- _______________________________________________________________________________
-
- »High-Level Device Manager Routines
-
- Note: As described in the File Manager chapter, the FSRead and FSWrite
- routines are also used to read from and write to files.
-
- FUNCTION OpenDriver (name: Str255; VAR refNum: INTEGER) : OSErr; [Not in ROM]
-
- OpenDriver opens the device driver specified by name and returns its reference number
- in refNum.
-
- Result codes noErr No error
- badUnitErr Bad reference number
- dInstErr Couldn’t find driver in resource file
- openErr Driver can’t perform the requested
- reading or writing
- unitEmptyErr Bad reference number
-
- FUNCTION CloseDriver (refNum: INTEGER) : OSErr; [Not in ROM]
-
- CloseDriver closes the device driver having the reference number refNum. Any pending
- I/O is completed, and the memory used by the driver is released.
-
- Warning: Before using this command to close a particular driver, refer
- to the chapter describing the driver for the consequences of
- closing it.
-
- Result codes noErr No error
- badUnitErr Bad reference number
- dRemoveErr Attempt to remove an open driver
- unitEmptyErr Bad reference number
-
- FUNCTION FSRead (refNum: INTEGER; VAR count: LONGINT;
- buffPtr: Ptr) : OSErr; [Not in ROM]
-
- FSRead attempts to read the number of bytes specified by the count parameter from the
- open device driver having the reference number refNum, and transfer them to the data
- buffer pointed to by buffPtr. After the read operation is completed, the number of
- bytes actually read is returned in the count parameter.
-
- Result codes noErr No error
- badUnitErr Bad reference number
- notOpenErr Driver isn’t open
- unitEmptyErr Bad reference number
- readErr Driver can’t respond to Read calls
-
- FUNCTION FSWrite (refNum: INTEGER; VAR count: LONGINT;
- buffPtr: Ptr) : OSErr; [Not in ROM]
-
- FSWrite takes the number of bytes specified by the count parameter from the buffer
- pointed to by buffPtr and attempts to write them to the open device driver having the
- reference number refNum. After the write operation is completed, the number of bytes
- actually written is returned in the count parameter.
-
- Result codes noErr No error
- badUnitErr Bad reference number
- notOpenErr Driver isn’t open
- unitEmptyErr Bad reference number
- writErr Driver can’t respond to Write calls
-
- FUNCTION Control (refNum: INTEGER; csCode: INTEGER;
- csParamPtr: Ptr) : OSErr; [Not in ROM]
-
- Control sends control information to the device driver having the reference number
- refNum. The type of information sent is specified by csCode, and the information
- itself is pointed to by csParamPtr. The values passed in csCode and pointed to by
- csParamPtr depend on the driver being called.
-
- Result codes noErr No error
- badUnitErr Bad reference number
- notOpenErr Driver isn’t open
- unitEmptyErr Bad reference number
- controlErr Driver can’t respond to this Control call
-
- FUNCTION Status (refNum: INTEGER; csCode: INTEGER;
- csParamPtr: Ptr) : OSErr; [Not in ROM]
-
- Status returns status information about the device driver having the reference number
- refNum. The type of information returned is specified by csCode, and the information
- itself is pointed to by csParamPtr. The values passed in csCode and pointed to by
- csParamPtr depend on the driver being called.
-
- Result codes noErr No error
- badUnitErr Bad reference number
- notOpenErr Driver isn’t open
- unitEmptyErr Bad reference number
- statusErr Driver can’t respond to this Status call
-
- FUNCTION KillIO (refNum: INTEGER) : OSErr; [Not in ROM]
-
- KillIO terminates all current and pending I/O with the device driver having the
- reference number refNum.
-
- Result codes noErr No error
- badUnitErr Bad reference number
- unitEmptyErr Bad reference number
-
- _______________________________________________________________________________
-
- »Low-Level Device Manager Routines
-
- This section contains special information for programmers using the low-level Pascal
- or assembly-language routines of the Device Manager, and describes them in detail.
-
- Note: The Device Manager routines for writing device drivers are
- described in the section “Writing Your Own Device Drivers”.
-
- All low-level Device Manager routines can be executed either synchronously
- (meaning that the application can’t continue until the routine is completed) or
- asynchronously (meaning that the application is free to perform other tasks while the
- routine is executing). Some cannot be executed asynchronously, because they use the
- Memory Manager to allocate and release memory.
-
- When an application calls a Device Manager routine asynchronously, an I/O request is
- placed in the driver I/O queue, and control returns to the calling program—possibly
- even before the actual I/O is completed. Requests are taken from the queue one at a
- time, and processed; meanwhile, the calling program is free to work on other things.
-
- The calling program may specify a completion routine to be executed at the end of an
- asynchronous operation.
-
- Routine parameters passed by an application to the Device Manager and returned by the
- Device Manager to an application are contained in a parameter block, which is a data
- structure in the heap or stack. All low-level Pascal calls to the Device Manager are
- of the form
-
- FUNCTION PBCallName (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
-
- PBCallName is the name of the routine. ParamBlock points to the parameter block
- containing the parameters for the routine. If async is TRUE, the call is executed
- asynchronously; otherwise the call is executed synchronously. Each call returns an
- integer result code of type OSErr.
-
- Assembly-language note: When you call a Device Manager routine, A0 must
- point to a parameter block containing the
- parameters for the routine. If you want the
- routine to be executed asynchronously, set bit 10
- of the routine trap word. You can do this by
- supplying the word ASYNC as the second argument
- to the routine macro. For example:
-
- _Read ,ASYNC
-
- You can set or test bit 10 of a trap word by using
- the global constant asyncTrpBit.
-
- If you want a routine to be executed immediately
- (bypassing the driver I/O queue), set bit 9 of the
- routine trap word. This can be accomplished by
- supplying the word IMMED as the second argument
- to the routine macro. (The driver must be able to
- handle immediate calls for this to work.) For example:
-
- _Write ,IMMED
-
- You can set or test bit 9 of a trap word by using
- the global constant noQueueBit. You can specify
- either ASYNC or IMMED, but not both. (The syntax
- shown above applies to the Macintosh Programmers
- Workshop Assembler; programmers using another
- development system should consult its documentation
- for the proper syntax.)
-
- All routines return a result code in D0.
-
- »Routine Parameters
-
- There are two different kinds of parameter blocks you’ll pass to Device Manager
- routines: one for I/O routines and another for Control and Status calls.
-
- The lengthy, variable-length data structure of a parameter block is given below. The
- Device Manager and File Manager use this same data structure, but only the parts
- relevant to the Device Manager are discussed here. Each kind of parameter block
- contains eight fields of standard information and three to nine fields of additional
- information:
-
- TYPE ParamBlkType = (ioParam,fileParam,volumeParam,cntrlParam);
-
- ParamBlockRec = RECORD
- qLink: QElemPtr; {next queue entry}
- qType: INTEGER; {queue type}
- ioTrap: INTEGER; {routine trap}
- ioCmdAddr: Ptr; {routine address}
- ioCompletion: ProcPtr; {completion routine}
- ioResult: OSErr; {result code}
- ioNamePtr: StringPtr; {driver name}
- ioVRefNum: INTEGER; {volume reference or }
- { drive number}
- CASE ParamBlkType OF
- ioParam:
- . . . {I/O routine parameters}
- fileParam:
- . . . {used by the File Manager}
- volumeParam:
- . . . {used by the File Manager}
- cntrlParam:
- . . . {Control and Status call parameters}
- END;
-
- ParmBlkPtr = ^ParamBlockRec;
-
- The first four fields in each parameter block are handled entirely by the Device
- Manager, and most programmers needn’t be concerned with them; programmers who are
- interested in them should see the section “The Structure of a Device Driver”.
-
- IOCompletion contains a pointer to a completion routine to be executed at the end of
- an asynchronous call; it should be NIL for asynchronous calls with no completion
- routine, and is automatically set to NIL for all synchronous calls.
-
- Warning: Completion routines are executed at the interrupt level and must
- preserve all registers other than A0, A1, and D0-D2. Your completion
- routine must not make any calls to the Memory Manager, directly or
- indirectly, and can’t depend on handles to unlocked blocks being
- valid. If it uses application globals, it must also ensure that
- register A5 contains the address of the boundary between the
- application globals and the application parameters; for details,
- see SetCurrentA5 and SetA5 in Macintosh Technical Note #208.
-
- •••Refer to Technical Note #208:•••
-
- Assembly-language note: When your completion routine is called, register A0
- points to the parameter block of the asynchronous
- call and register D0 contains the result code.
-
- Routines that are executed asynchronously return control to the calling program with
- the result code noErr as soon as the call is placed in the driver I/O queue. This
- isn’t an indication of successful call completion, but simply indicates that the call
- was successfully queued. To determine when the call is actually completed, you can
- poll the ioResult field; this field is set to 1 when the call is made, and receives
- the actual result code upon completion of the call. Completion routines are executed
- after the result code is placed in ioResult.
-
- IONamePtr is a pointer to the name of a driver and is used only for calls to the Open
- function. IOVRefNum is used by the Disk Driver to identify drives.
-
- I/O routines use the following additional fields:
-
- ioParam:
- (ioRefNum: INTEGER; {driver reference number}
- ioVersNum: SignedByte; {not used}
- ioPermssn: SignedByte; {read/write permission}
- ioMisc: Ptr; {not used}
- ioBuffer: Ptr; {pointer to data buffer}
- ioReqCount: LONGINT; {requested number of bytes}
- ioActCount: LONGINT; {actual number of bytes}
- ioPosMode: INTEGER; {positioning mode}
- ioPosOffset: LONGINT); {positioning offset}
-
- IOPermssn requests permission to read from or write to a driver when the driver is
- opened, and must contain one of the following values:
-
- CONST fsCurPerm = 0; {whatever is currently allowed}
- fsRdPerm = 1; {request to read only}
- fsWrPerm = 2; {request to write only}
- fsRdWrPerm = 3; {request to read and write}
-
- This request is compared with the capabilities of the driver (some drivers are read-only,
- some are write-only). If the driver is incapable of performing as requested, a result
- code indicating the error is returned.
-
- IOBuffer points to a data buffer into which data is written by Read calls and from
- which data is read by Write calls. IOReqCount specifies the requested number of bytes
- to be read or written. IOActCount contains the number of bytes actually read or
- written.
-
- IOPosMode and ioPosOffset contain positioning information used for Read and Write
- calls by drivers of block devices. IOPosMode contains the positioning mode; bits 0
- and 1 indicate where an operation should begin relative to the physical beginning of
- the block-formatted medium (such as a disk). You can use the following predefined
- constants to test or set the value of these bits:
-
- CONST fsAtMark = 0; {at current position}
- fsFromStar = 1; {offset relative to beginning of medium}
- fsFromMark = 3; {offset relative to current position}
-
- IOPosOffset specifies the byte offset (either positive or negative), relative to the
- position specified by the positioning mode, where the operation will be performed
- (except when the positioning mode is fsAtMark, in which case ioPosOffset is ignored).
- IOPosOffset must be a 512-byte multiple.
-
- To verify that data written to a block device matches the data in memory, make a Read
- call right after the Write call. The parameters for a read-verify operation are the
- same as for a standard Read call, except that the following constant must be added to
- the positioning mode:
-
- CONST rdVerify = 64; {read-verify mode}
-
- The result code ioErr is returned if any of the data doesn’t match.
-
- Control and Status calls use three additional fields:
-
- cntrlParam:
- (ioCRefNum: INTEGER; {driver reference number}
- csCode: INTEGER; {type of Control or Status call}
- csParam: ARRAY[0..10] OF INTEGER); {control or status information}
-
- IOCRefNum contains the reference number of the device driver. The csCode field contains
- a number identifying the type of call; this number may be interpreted differently by
- each driver. The csParam field contains the control or status information for the
- call; it’s declared as up to 22 bytes of information because its exact contents will
- vary from one Control or Status call to the next. To store information in this field,
- you must perform the proper type coercion.
- _______________________________________________________________________________
-
- »Routine Descriptions
-
- This section describes the procedures and functions. Each routine description includes
- the low-level Pascal form of the call and the routine’s assembly-language macro. A
- list of the fields in the parameter block affected by the call is also given.
-
- Assembly-language note: The field names given in these descriptions are
- those of the ParamBlockRec data type; see the
- summary at the end of this chapter for the names
- of the corresponding assembly-language offsets.
- (The names for some offsets differ from their
- Pascal equivalents, and in certain cases more than
- one name for the same offset is provided.)
-
- The number next to each parameter name indicates the byte offset of the parameter
- from the start of the parameter block pointed to by register A0; only assembly-language
- programmers need be concerned with it. An arrow next to each parameter name indicates
- whether it’s an input, output, or input/output parameter:
-
- Arrow Meaning
-
- --> Parameter is passed to the routine
- <-- Parameter is returned by the routine
- <-> Parameter is passed to and returned by the routine
-
- Note: As described in the File Manager chapter, the Open and Close
- functions are also used to open and close files.
-
- FUNCTION PBOpen (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
-
- Parameter block
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 18 ioNamePtr pointer
- <-- 24 ioRefNum word
- --> 27 ioPermssn byte
-
- PBOpen opens the device driver specified by ioNamePtr, reading it into memory if
- necessary, and returns its reference number in ioRefNum. IOPermssn specifies the
- requested read/write permission.
-
- Result codes noErr No error
- badUnitErr Bad reference number
- dInstErr Couldn’t find driver in resource file
- openErr Driver can’t perform the requested
- reading or writing
- unitEmptyErr Bad reference number
-
- FUNCTION PBClose (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
-
- Trap macro _Close
-
- Parameter block
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 24 ioRefNum word
-
- PBClose closes the device driver having the reference number ioRefNum. Any pending
- I/O is completed, and the memory used by the driver is released.
-
- Result codes noErr No error
- badUnitErr Bad reference number
- dRemovErr Attempt to remove an open driver
- unitEmptyErr Bad reference number
-
- FUNCTION PBRead (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
-
- Trap macro _Read
-
- •••Refer to Technical Note #187:•••
-
- Parameter block
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 22 ioVRefNum word
- --> 24 ioRefNum word
- --> 32 ioBuffer pointer
- --> 36 ioReqCount long word
- <-- 40 ioActCount long word
- --> 44 ioPosMode word
- <-> 46 ioPosOffset long word
-
- PBRead attempts to read ioReqCount bytes from the device driver having the reference
- number ioRefNum, and transfer them to the data buffer pointed to by ioBuffer. The
- drive number, if any, of the device to be read from is specified by ioVRefNum. After
- the read is completed, the position is returned in ioPosOffset and the number of
- bytes actually read is returned in ioActCount.
-
- Result codes noErr No error
- badUnitErr Bad reference number
- notOpenErr Driver isn’t open
- unitEmptyErr Bad reference number
- readErr Driver can’t respond to Read calls
-
- FUNCTION PBWrite (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
-
- Trap macro _Write
-
- •••Refer to Technical Note #187:•••
-
- Parameter block
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 22 ioVRefNum word
- --> 24 ioRefNum word
- --> 32 ioBuffer pointer
- --> 36 ioReqCount long word
- <-- 40 ioActCount long word
- --> 44 ioPosMode word
- <-> 46 ioPosOffset long word
-
- PBWrite takes ioReqCount bytes from the buffer pointed to by ioBuffer and attempts to
- write them to the device driver having the reference number ioRefNum. The drive
- number, if any, of the device to be written to is specified by ioVRefNum. After the
- write is completed, the position is returned in ioPosOffset and the number of bytes
- actually written is returned in ioActCount.
-
- Result codes noErr No error
- badUnitErr Bad reference number
- notOpenErr Driver isn’t open
- unitEmptyErr Bad reference number
- writErr Driver can’t respond to Write calls
-
- FUNCTION PBControl (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
-
- Trap macro _Control
-
- Parameter block
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 22 ioVRefNum word
- --> 24 ioRefNum word
- --> 26 csCode word
- --> 28 csParam record
-
- PBControl sends control information to the device driver having the reference number
- ioRefNum; the drive number, if any, is specified by ioVRefNum. The type of information
- sent is specified by csCode, and the information itself begins at csParam. The values
- passed in csCode and csParam depend on the driver being called.
-
- Result codes noErr No error
- badUnitErr Bad reference number
- notOpenErr Driver isn’t open
- unitEmptyErr Bad reference number
- controlErr Driver can’t respond to this Control call
-
- FUNCTION PBStatus (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
-
- Trap macro _Status
-
- Parameter block
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 22 ioVRefNum word
- --> 24 ioRefNum word
- --> 26 csCode word
- <-- 28 csParam record
-
- PBStatus returns status information about the device driver having the reference
- number ioRefNum; the drive number, if any, is specified by ioVRefNum. The type of
- information returned is specified by csCode, and the information itself begins at
- csParam. The values passed in csCode and csParam depend on the driver being called.
-
- Result codes noErr No error
- badUnitErr Bad reference number
- notOpenErr Driver isn’t open
- unitEmptyErr Bad reference number
- statusErr Driver can’t respond to this Status call
-
- FUNCTION PBKillIO (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
-
- Trap macro _KillIO
-
- Parameter block
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 24 ioRefNum word
-
- PBKillIO stops any current I/O request being processed, and removes all pending I/O
- requests from the I/O queue of the device driver having the reference number ioRefNum.
- The completion routine of each pending I/O request is called, with the ioResult field
- of each request equal to the result code abortErr.
-
- Result codes noErr No error
- badUnitErr Bad reference number
- unitEmptyErr Bad reference number
-
- _______________________________________________________________________________
-
-
- æKY The…Structure…of…a…Device…Driver
- æC »THE STRUCTURE OF A DEVICE DRIVER DeviceManager
- _______________________________________________________________________________
-
- This section describes the structure of device drivers for programmers interested in
- writing their own driver or manipulating existing drivers. Some of the information
- presented here is accessible only through assembly language.
-
- RAM drivers are stored in resource files. The resource type for drivers is
- 'DRVR'. The resource name is the driver name. The resource ID for a driver is its
- unit number (explained below) and must be between 0 and 31 inclusive.
-
- Warning: Don’t use the unit number of an existing driver unless you
- want the existing driver to be replaced.
-
- As shown in Figure 2, a driver begins with a few words of flags and other data,
- followed by offsets to the routines that do the work of the driver, an optional
- title, and finally the routines themselves.
-
- Every driver contains a routine to handle Open and Close calls, and may contain
- routines to handle Read, Write, Control, Status, and KillIO calls. The driver routines
- that handle Device Manager calls are as follows:
-
- Device Manager call Driver routine
-
- Open Open
- Read Prime
- Write Prime
- Control Control
- KillIO Control
- Status Status
- Close Close
-
- •••Refer to Figure 2.•••
-
- Figure 2–Driver Structure
-
- For example, when a KillIO call is made to a driver, the driver’s control routine
- must implement the call.
-
- Each bit of the high-order byte of the drvrFlags word contains a flag:
-
- dReadEnable .EQU 0 ;set if driver can respond to Read calls
- dWritEnable .EQU 1 ;set if driver can respond to Write calls
- dCtlEnable .EQU 2 ;set if driver can respond to Control calls
- dStatEnable .EQU 3 ;set if driver can respond to Status calls
- dNeedGoodBye .EQU 4 ;set if driver needs to be called before
- ; the application heap is reinitialized
- dNeedTime .EQU 5 ;set if driver needs time for performing
- ; a periodic action
- dNeedLock .EQU 6 ;set if driver will be locked in memory as
- ; soon as it's opened (always set for ROM drivers)
-
- Bits 8-11 (bits 0-3 of the high-order byte) indicate which Device Manager calls the
- driver’s routines can respond to.
-
- Unlocked RAM drivers in the application heap will be lost every time the heap is
- reinitialized (when an application starts up, for example). If dNeedGoodBye is set,
- the control routine of the device driver will be called before the heap is reinitialized,
- and the driver can perform any “clean-up” actions it needs to. The driver’s control
- routine identifies this “good-bye” call by checking the csCode parameter—it will be
- the global constant
-
- goodBye .EQU -1 ;heap will be reinitialized, clean up if necessary
-
- Device drivers may need to perform predefined actions periodically. For example, a
- network driver may want to poll its input buffer every ten seconds to see if it has
- received any messages. If the dNeedTime flag is set, the driver does need to perform
- a periodic action, and the drvrDelay word contains a tick count indicating how often
- the periodic action should occur. A tick count of 0 means it should happen as often
- as possible, 1 means it should happen at most every sixtieth of a second, 2 means at
- most every thirtieth of a second, and so on. Whether the action actually occurs this
- frequently depends on how often the application calls the Desk Manager procedure
- SystemTask. SystemTask calls the driver’s control routine (if the time indicated by
- drvrDelay has elapsed), and the control routine must perform whatever predefined
- action is desired. The driver’s control routine identifies the SystemTask call by
- checking the csCode parameter—it will be the global constant
-
- accRun .EQU 65 ;take the periodic action, if any, for this driver
-
- Note: Some drivers may not want to rely on the application to call
- SystemTask. The Vertical Retrace Manager and Time Manager both offer
- the ability to perform tasks periodically. Both of these alternatives,
- however, perform these tasks at interrupt time, and there are certain
- restrictions on tasks performed during interrupts, such as not
- being able to make calls to the Memory Manager. For more information
- on these restrictions, see the Vertical Retrace Manager, and Time
- Manager chapters. Tasks that are time consuming may be able to take
- advantage of the Deferred Task Manager, which will allow other
- interrupts to be processed. Periodic actions performed in response to
- SystemTask calls are not performed via an interrupt and so don’t have
- these restrictions.
-
- DrvrEMask and drvrMenu are used only for desk accessories and are discussed in the
- Desk Manager chapter.
-
- Following drvrMenu are the offsets to the driver routines, a title for the driver
- (preceded by its length in bytes), and the routines that do the work of the driver.
-
- Note: Each of the driver routines must be aligned on a word boundary.
-
- _______________________________________________________________________________
-
- »Device Control Entry
-
- The first time a driver is opened, information about it is read into a structure in
- memory called a device control entry. A device control entry contains the header of
- the driver’s I/O queue, the location of the driver’s routines, and other information.
- A device control entry is a 40-byte relocatable block located in the system heap.
- It’s locked while the driver is open, and unlocked while the driver is closed.
-
- Most of the data in the device control entry is stored and accessed only by the
- Device Manager, but in some cases the driver itself must store into it. The structure
- of a device control entry is shown below; note that the first four words of the
- driver are copied into the dCtlFlags, dCtlDelay, dCtlEMask, and dCtlMenu fields.
-
- TYPE DCtlEntry = RECORD
- dCtlDriver: Ptr; {pointer to ROM driver or }
- { handle to RAM driver}
- dCtlFlags: INTEGER; {flags}
- dCtlQHdr: QHdr; {driver I/O queue header}
- dCtlPosition: LONGINT; {byte position used by Read }
- { and Write calls}
- dCtlStorage: Handle; {handle to RAM driver's }
- { private storage}
- dCtlRefNum: INTEGER; {driver reference number}
- dCtlCurTicks: LONGINT; {used internally}
- dCtlWindow: WindowPtr; {pointer to driver's window}
- dCtlDelay: INTEGER; {number of ticks between }
- { periodic actions}
- dCtlEMask: INTEGER; {desk accessory event mask}
- dCtlMenu: INTEGER {menu ID of menu associated
- { with driver}
- END;
-
- DCtlPtr = ^DCtlEntry;
- DCtlHandle = ^DCtlPtr;
-
- The low-order byte of the dCtlFlags word contains the following flags:
-
- Bit number Meaning
-
- 5 Set if driver is open
- 6 Set if driver is RAM-based
- 7 Set if driver is currently executing
-
- Assembly-language note: These flags can be accessed with the global
- constants dOpened, dRAMBased, and drvrActive.
-
- The high-order byte of the dCtlFlags word contains flags copied from the drvrFlags
- word of the driver, as described above.
-
- DCtlQHdr contains the header of the driver’s I/O queue (described below). DCtlPosition
- is used only by drivers of block devices, and indicates the current source or destination
- position of a Read or Write call. The position is given as a number of bytes beyond
- the physical beginning of the medium used by the device. For example, if one logical
- block of data has just been read from a 3 1/2-inch disk via the Disk Driver, dCtlPosition
- will be 512.
-
- ROM drivers generally use locations in low memory for their local storage. RAM drivers
- may reserve memory within their code space, or allocate a relocatable block and keep
- a handle to it in dCtlStorage (if the block resides in the application heap, its
- handle will be set to NIL when the heap is reinitialized).
-
- You can get a handle to a driver’s device control entry by calling the Device Manager
- function GetDCtlEntry.
-
- FUNCTION GetDCtlEntry (refNum: INTEGER) : DCtlHandle; [Not in ROM]
-
- GetDCtlEntry returns a handle to the device control entry of the device driver having
- the reference number refNum.
-
- Assembly-language note: You can get a handle to a driver’s device control
- entry from the unit table, as described below.
-
- _______________________________________________________________________________
-
- »The Driver I/O Queue
-
- Each device driver has a driver I/O queue; this is a standard Operating System queue
- (described in the Operating System Utilities chapter) that contains the parameter
- blocks for all asynchronous routines awaiting execution. Each time a routine is
- called, the driver places an entry in the queue; each time a routine is completed,
- its entry is removed from the queue. The queue’s header is located in the dCtlQHdr
- field of the driver’s device control entry. The low-order byte of the queue flags
- field in the queue header contains the version number of the driver, and can be used
- for distinguishing between different versions of the same driver.
-
- Each entry in the driver I/O queue consists of a parameter block for the routine that
- was called. Most of the fields of this parameter block contain information needed by
- the specific Device Manager routines; these fields are explained above in the section
- “Low-Level Device Manager Routines”. The first four fields of this parameter block,
- shown below, are used by the Device Manager in processing the I/O requests in the
- queue.
-
- TYPE ParamBlockRec = RECORD
- qLink: QElemPtr; {next queue entry}
- qType: INTEGER; {queue type}
- ioTrap: INTEGER; {routine trap}
- ioCmdAddr: Ptr; {routine address}
- . . . {rest of block}
- END;
-
- QLink points to the next entry in the queue, and qType indicates the queue type,
- which must always be ORD(ioQType). IOTrap and ioCmdAddr contain the trap and address
- of the Device Manager routine that was called.
-
- _______________________________________________________________________________
-
- »The Unit Table
-
- The location of each device control entry is maintained in a list called the unit
- table. The unit table is a 128-byte nonrelocatable block containing 32 four-byte
- entries. Each entry has a number, from 0 to 31, called the unit number, and contains
- a handle to the device control entry for a driver. The unit number can be used as an
- index into the unit table to locate the handle to a specific driver’s device control
- entry; it’s equal to
-
- –1 * (refNum + 1)
-
- where refNum is the driver reference number. For example, the Sound Driver’s reference
- number is –4 and its unit number is 3.
-
- Figure 3 shows the layout of the unit table with the standard drivers and desk accessories
- installed.
-
- •••Refer to Figure 3.•••
-
- Figure 3–The Unit Table
-
- Warning: Any new drivers contained in resource files should have resource
- IDs that don’t conflict with the unit numbers of existing
- drivers—unless you want an existing driver to be replaced. Be
- sure to check the unit table before installing a new driver;
- the base address of the unit table is stored in the global
- variable UTableBase.
-
- •••Refer to Technical Note #71:•••
-
- _______________________________________________________________________________
-
-
- æKY Writing…Your…Own…Device…Drivers
- æC »WRITING YOUR OWN DEVICE DRIVERS DeviceManager
- _______________________________________________________________________________
-
- Drivers are usually written in assembly language. The structure of your driver must
- match that shown in the previous section. The routines that do the work of the driver
- should be written to operate the device in whatever way you require. Your driver must
- contain routines to handle Open and Close calls, and may choose to handle Read,
- Write, Control, Status, and KillIO calls as well.
-
- Warning: A device driver doesn’t “own” the hardware it operates, and has
- no way of determining whether another driver is attempting to
- use that hardware at the same time. There’s a possiblity of
- conflict in situations where two drivers that operate the same
- device are installed concurrently.
-
- When the Device Manager executes a driver routine to handle an application call, it
- passes a pointer to the call’s parameter block in register A0 and a pointer to the
- driver’s device control entry in register A1. From this information, the driver can
- determine exactly what operations are required to fulfill the call’s requests, and do
- them.
-
- Open and close routines must execute synchronously and return via an RTS instruction.
- They needn’t preserve any registers that they use. Close routines should put a result
- code in register D0. Since the Device Manager sets D0 to 0 upon return from an Open
- call, open routines should instead place the result code in the ioResult field of the
- parameter block.
-
- The open routine must allocate any private storage required by the driver, store a
- handle to it in the device control entry (in the dCtlStorage field), initialize any
- local variables, and then be ready to receive a Read, Write, Status, Control, or
- KillIO call. It might also install interrupt handlers, change interrupt vectors, and
- store a pointer to the device control entry somewhere in its local storage for its
- interrupt handlers to use. The close routine must reverse the effects of the open
- routine, by releasing all used memory, removing interrupt handlers, and replacing
- changed interrupt vectors. If anything about the operational state of the driver
- should be saved until the next time the driver is opened, it should be kept in the
- relocatable block of memory pointed to by dCtlStorage.
-
- Prime, control, and status routines must be able to respond to queued calls and
- asynchronous calls, and should be interrupt-driven. Asynchronous portions of the
- routines can use registers A0-A3 and D0-D3, but must preserve any other registers
- used; synchronous portions can use all registers. Prime, control, and status routines
- should return a result code in D0. They must return via an RTS if called immediately
- (with noQueueBit set in the ioTrap field) or if the device couldn’t complete the I/O
- request right away, or via a JMP to the IODone routine (explained below) if not
- called immediately and if the device completed the request.
-
- Warning: If the prime, control, and status routines can be called as the
- result of an interrupt, they must preserve all registers other
- than A0, A1, and D0-D2. They can’t make any calls to the Memory
- Manager and cannot depend on unlocked handles being valid. If
- they use application globals, they must also ensure that register
- A5 contains the address of the boundary between the application
- globals and the application parameters; for details, refer to
- SetCurrentA5 and SetA5 in Macintosh Technical Note #208.
-
- •••Refer to Technical Note #208:•••
-
- The prime routine implements Read and Write calls made to the driver. It can distinguish
- between Read and Write calls by comparing the low-order byte of the ioTrap field with
- the following predefined constants:
-
- aRdCmd .EQU 2 ;Read call
- aWrCmd .EQU 3 ;Write call
-
- You may want to use the Fetch and Stash routines (described below) to read and write
- characters. If the driver is for a block device, it should update the dCtlPosition
- field of the device control entry after each read or write.
-
- The control routine accepts the control information passed to it, and manipulates the
- device as requested. The status routine returns requested status information. Since
- both the control and status routines may be subjected to Control and Status calls
- sending and requesting a variety of information, they must be prepared to respond
- correctly to all types. The control routine must handle KillIO calls. The driver
- identifies KillIO calls by checking the csCode parameter—it will be the global constant
-
- killCode .EQU 1 ;handle the KillIO call
-
- Warning: KillIO calls must return via an RTS, and shouldn’t jump
- (via JMP) to the IODone routine.
-
- _______________________________________________________________________________
-
- »Routines for Writing Drivers
-
- The Device Manager includes three routines—Fetch, Stash, and IODone—that provide
- low-level support for driver routines. These routines can be used only with a pending,
- asynchronous request; include them in the code of your device driver if they’re
- useful to you. A pointer to the device control entry is passed to each of these
- routines in register A1. The device control entry contains the driver I/O queue
- header, which is used to locate the pending request. If there are no pending requests,
- these routines generate the system error dsIOCoreErr (see the System Error Handler
- chapter for more information).
-
- •••Refer to Technical Notes #36, #108, & 187:•••
- •••Refer to Technical Note #257 & Q & A Stack.•••
-
- Fetch, Stash, and IODone are invoked via “jump vectors” (stored in the global variables
- JFetch, JStash, and JIODone) rather than macros, in the interest of speed. You use a
- jump vector by moving its address onto the stack. For example:
-
- MOVE.L JIODone,-(SP)
- RTS
-
- Fetch and Stash don’t return a result code; if an error occurs, the System Error
- Handler is invoked. IODone may return a result code.
-
- Fetch function
-
- Jump vector JFetch
- On entry A1: pointer to device control entry
- On exit D0: character fetched; bit 15=1 if it’s the last
- character in data buffer
-
- Fetch gets the next character from the data buffer pointed to by ioBuffer and places
- it in D0. IOActCount is incremented by 1. If ioActCount equals ioReqCount, bit 15 of
- D0 is set. After receiving the last byte requested, the driver should call IODone.
-
- Stash function
-
- Jump vector JStash
- On entry A1: pointer to device control entry
- D0: character to stash
- On exit D0: bit 15=1 if it’s the last character requested
-
- Stash places the character in D0 into the data buffer pointed to by ioBuffer, and
- increments ioActCount by 1. If ioActCount equals ioReqCount, bit 15 of D0 is set.
- After stashing the last byte requested, the driver should call IODone.
-
- IODone function
-
- Jump vector JIODone
- On entry A1: pointer to device control entry
- D0: result code (word)
-
- IODone removes the current I/O request from the driver I/O queue, marks the driver
- inactive, unlocks the driver and its device control entry (if it’s allowed to by the
- dNeedLock bit of the dCtlFlags word), and executes the completion routine (if there
- is one). Then it begins executing the next I/O request in the driver I/O queue.
-
- Warning: Due to the way the File Manager does directory lookups, block
- device drivers should take care to support asynchronous I/O
- operations. If the driver’s prime routine has completed an
- asynchronous Read or Write call just prior to calling IODone
- and its completion routine starts an additional Read or Write,
- large amounts of the stack may be used (potentially causing the
- stack to expand into the heap). To avoid this problem, the prime
- routine should exit via an RTS instruction and then jump to IODone
- via an interrupt.
-
-
- _______________________________________________________________________________
-
-
- æKY Interrupts
- æC »INTERRUPTS DeviceManager
- _______________________________________________________________________________
-
- This section discusses how interrupts are used on the Macintosh 128K and 512K specifically.
- The general philosophy applies to all Macintosh computers. Only programmers who want
- to write interrupt-driven device drivers need read this section.
-
- Warning: Only the Macintosh 128K and 512K are covered in this section.
- Much of the information presented here is hardware-dependent;
- programmers are encouraged to write code that’s hardware-independent
- to ensure compatibility with future versions of the Macintosh.
-
- An interrupt is a form of exception: an error or abnormal condition detected by the
- processor in the course of program execution. Specifically, an interrupt is an exception
- that’s signaled to the processor by a device, as distinct from a trap, which arises
- directly from the execution of an instruction. Interrupts are used by devices to
- notify the processor of a change in condition of the device, such as the completion
- of an I/O request. An interrupt causes the processor to suspend normal execution,
- save the address of the next instruction and the processor’s internal status on the
- stack, and execute an interrupt handler.
-
- The MC68000 recognizes seven different levels of interrupt, each with its own interrupt
- handler. The addresses of the various handlers, called interrupt vectors, are kept in
- a vector table in low memory. Each level of interrupt has its own vector located in
- the vector table. When an interrupt occurs, the processor fetches the proper vector
- from the table, uses it to locate the interrupt handler for that level of interrupt,
- and jumps to the handler. On completion, the handler restores the internal status of
- the processor from the stack and resumes normal execution from the point of suspension.
-
- There are three devices that can create interrupts: the Synertek SY6522 Versatile
- Interface Adapter (VIA), the Zilog Z8530 Serial Communications Controller (SCC), and
- the debugging switch. They send a three-bit number called the interrupt priority
- level to the processor. This number indicates which device is interrupting, and which
- interrupt handler should be executed:
-
- Level Interrupting device
-
- 0 None
- 1 VIA
- 2 SCC
- 3 VIA and SCC
- 4-7 Debugging switch
-
- A level-3 interrupt occurs when both the VIA and the SCC interrupt at the same instant;
- the interrupt handler for a level-3 interrupt is simply an RTE instruction. Debugging
- interrupts shouldn’t occur during the normal execution of an application.
-
- The interrupt priority level is compared with the processor priority in bits
- 8-10 of the status register. If the interrupt priority level is greater than the
- processor priority, the MC68000 acknowledges the interrupt and initiates interrupt
- processing. The processor priority determines which interrupting devices are ignored,
- and which are serviced:
-
- Level Services
-
- 0 All interrupts
- 1 SCC and debugging interrupts only
- 2-6 Debugging interrupts only
- 7 No interrupts
-
- When an interrupt is acknowledged, the processor priority is set to the interrupt
- priority level, to prevent additional interrupts of equal or lower priority, until
- the interrupt handler has finished servicing the interrupt.
-
- The interrupt priority level is used as an index into the primary interrupt vector
- table. This table contains seven long words beginning at address $64. Each long word
- contains the starting address of an interrupt handler (see Figure 4).
-
- Execution jumps to the interrupt handler at the address specified in the table. The
- interrupt handler must identify and service the interrupt. Then it must restore the
- processor priority, status register, and program counter to the values they contained
- before the interrupt occurred.
-
- •••Refer to Figure 4.•••
-
- Figure 4–Primary Interrupt Vector Table
-
- _______________________________________________________________________________
-
- »Level-1 (VIA) Interrupts
-
- Level-1 interrupts are generated by the VIA. You’ll need to read the Synertek manual
- describing the VIA to use most of the information provided in this section. The
- level-1 interrupt handler determines the source of the interrupt
- (via the VIA’s interrupt flag register and interrupt enable register) and then uses a
- table of secondary vectors in low memory to determine which interrupt handler to call
- (see Figure 5).
-
- •••Refer to Figure 5.•••
-
- Figure 5–Level-1 Secondary Interrupt Vector Table
-
- The level-1 secondary interrupt vector table is stored in the global variable Lvl1DT.
- Each vector in the table points to the interrupt handler for a different source of
- interrupt. The interrupts are handled in order of their entry in the table, and only
- one interrupt handler is called per level-1 interrupt (even if two or more sources
- are interrupting). This allows the
- level-1 interrupt handler to be reentrant; interrupt handlers should lower the processor
- priority as soon as possible in order to enable other pending interrupts to be processed.
-
- The one-second interrupt updates the global variable Time (explained in the Operating
- System Utilities chapter); it’s also used for inverting (“blinking”) the apple symbol
- in the menu bar when the alarm goes off. Vertical retrace interrupts are generated
- once every vertical retrace interval; control is passed to the Vertical Retrace
- Manager, which performs recurrent system tasks
- (such as updating the global variable Ticks) and executes tasks installed by the
- application. (For more information, see the Vertical Retrace Manager chapter.)
-
- If the cumulative elapsed time for all tasks during a vertical retrace interrupt
- exceeds about 16 milliseconds (one video frame), the vertical retrace interrupt may
- itself be interrupted by another vertical retrace interrupt. In this case, tasks to
- be performed during the second vertical retrace interrupt are ignored, with one
- exception: The global variable Ticks will still be updated.
-
- The shift-register interrupt is used by the keyboard and mouse interrupt handlers.
- Whenever the Disk Driver or Sound Driver isn’t being used, you can use the T1 and T2
- timers for your own needs; there’s no way to tell, however, when they’ll be needed
- again by the Disk Driver or Sound Driver.
-
- The base address of the VIA (stored in the global variable VIA) is passed to each
- interrupt handler in register A1.
-
- _______________________________________________________________________________
-
- »Level-2 (SCC) Interrupts
-
- Level-2 interrupts are generated by the SCC. You’ll need to read the Zilog manual
- describing the SCC to effectively use the information provided in this section. The
- level-2 interrupt handler determines the source of the interrupt, and then uses a
- table of secondary vectors in low memory to determine which interrupt handler to call
- (see Figure 6).
-
- •••Refer to Figure 6.•••
-
- Figure 6–Level-2 Secondary Interrupt Vector Table
-
- The level-2 secondary interrupt vector table is stored in the global variable Lvl2DT.
- Each vector in the table points to the interrupt handler for a different source of
- interrupt. The interrupts are handled according to the following fixed priority:
-
- channel A receive character available and special receive
- channel A transmit buffer empty
- channel A external/status change
- channel B receive character available and special receive
- channel B transmit buffer empty
- channel B external/status change
-
- Only one interrupt handler is called per level-2 interrupt (even if two or more
- sources are interrupting). This allows the level-2 interrupt handler to be reentrant;
- interrupt handlers should lower the processor priority as soon as possible in order
- to enable other pending interrupts to be processed.
-
- External/status interrupts pass through a tertiary vector table in low memory to
- determine which interrupt handler to call (see Figure 7).
-
- •••Refer to Figure 7.•••
-
- Figure 7–Level-2 External/Status Interrupt Vector Table
-
- The external/status interrupt vector table is stored in the global variable ExtStsDT.
- Each vector in the table points to the interrupt handler for a different source of
- interrupt. Communications interrupts (break/abort, for example) are always handled
- before mouse interrupts.
-
- When a level-2 interrupt handler is called, D0 contains the address of the SCC read
- register 0 (external/status interrupts only), and D1 contains the bits of read register
- 0 that have changed since the last external/status interrupt. A0 points to the SCC
- channel A or channel B control read address and A1 points to SCC channel A or channel
- B control write address, depending on which channel is interrupting. The SCC’s data
- read address and data write address are located four bytes beyond A0 and A1, respectively;
- they’re also contained in the global variables SCCWr and SCCRd. You can use the
- following predefined constants as offsets from these base addresses to locate the SCC
- control and data lines:
-
- aData .EQU 6 ;channel A data in or out
- aCtl .EQU 2 ;channel A control
- bData .EQU 4 ;channel B data in or out
- bCtl .EQU 0 ;channel B control
-
- _______________________________________________________________________________
-
- »Writing Your Own Interrupt Handlers
-
- You can write your own interrupt handlers to replace any of the standard interrupt
- handlers just described. Be sure to place a vector that points to your interrupt
- handler in one of the vector tables.
-
- Both the level-1 and level-2 interrupt handlers preserve registers A0-A3 and
- D0-D3. Every interrupt handler (except for external/status interrupt handlers) is
- responsible for clearing the source of the interrupt, and for saving and restoring
- any additional registers used. Interrupt handlers should return directly via an RTS
- instruction, unless the interrupt is completing an asynchronous call, in which case
- they should jump (via JMP) to the IODone routine.
-
- _______________________________________________________________________________
-
-
- æKY The…Chooser
- æC »THE CHOOSER DeviceManager
- _______________________________________________________________________________
-
- Note: The extensions to the Device Manager described in the following
- section were originally documented in Inside Macintosh, Volume IV.
- As such, this information refers to the 128K ROMs and System file
- version 3.2 and later.
-
- The Chooser is a desk accessory that provides a standard interface to help solicit
- and accept specific choices from the user. It allows new device drivers to prompt the
- user for choices such as which serial port to use, which AppleTalk zone to communicate
- with, and which LaserWriter to use.
-
- The Chooser relies heavily on the List Manager for creating, displaying, and manipulating
- possible user selections. The List Manager is described in the List Manager chapter.
-
- Under the Chooser, each device is represented by a device resource file in the system
- folder on the user’s system startup disk. (This is an extension of the concept of
- printer resource files, described in the Printing Manager chapter.) The Chooser
- accepts three types of device resource files to identify different kinds of devices:
-
- File type Device type
-
- 'PRES' Serial printer
- 'PRER' Non-serial printer
- 'RDEV' Other device
-
- The creator of each file is left undefined, allowing each device to have its own
- icon.
-
- In addition to any actual driver code, each device resource file of type 'PRER' or
- 'RDEV' contains a set of resources that tell the Chooser how to handle the device.
- These resources include:
-
- Resource type Resource ID Description
-
- 'PACK' –4096 Device package (described below)
- 'STR ' –4096 Type name for AppleTalk devices
- 'GNRL' –4096 NBP timeout and retry information
- for AppleTalk devices
- 'STR ' –4093 Left button title
- 'STR ' –4092 Right button title
- 'STR ' –4091 String for Chooser to use to label
- the list when choosing the device
- 'BNDL' Icon information
- 'STR ' –4090 Reserved for use by the Chooser
-
- Warning: You should give your device type a distinctive icon, since this
- may be the only way that devices are identified in the Chooser’s
- screen display.
-
- Device resource files of type 'PRES' (serial printers) contain only the driver code,
- without any of the resources listed above. The configuration of such devices is
- implemented entirely by the Chooser.
-
- _______________________________________________________________________________
-
- »The Device Package
-
- The device package is usually written in assembly language, but may be written partially
- in Pascal. The assembly-language structure of the 'PACK' –4096 resource is as follows:
-
- Offset (hex) Word
-
- 0 BRA.S to offset $10
- 2 Device ID (word)
- 4 'PACK' (long word)
- 8 $F000 (–4096)
- A Version (word)
- C Flags (long word)
- 10 Start of driver code
-
- The device ID is an integer that identifies the device. The version word differentiates
- versions of the driver code. The flags field contains the following information:
-
- Bit Meaning
-
- 31 Set if an AppleTalk device
- 30–29 Reserved (clear to 0)
- 28 Set if device package can have multiple instances selected at once
- 27 Set if device package uses left button
- 26 Set if device package uses right button
- 25 Set if no saved zone name
- 24 Set if device package uses actual zone names
- 23–17 Reserved (clear to 0)
- 16 Set if device package accepts the newSel message
- 15 Set if device package accepts the fillList message
- 14 Set if device package accepts the getSel message
- 13 Set if device package accepts the select message
- 12 Set if device package accepts the deselect message
- 11 Set if device package accepts the terminate message
- 10–0 Reserved (clear to 0)
-
- _______________________________________________________________________________
-
- »Communication with the Chooser
-
- The Chooser communicates with device packages as if they were the following function:
-
- FUNCTION Device (message,caller: INTEGER; objName,zoneName: StringPtr;
- p1,p2: LONGINT) : OSErr;
-
- The message parameter identifies the operation to be performed. It has one of the
- following values:
-
- CONST newSelMsg = 12; {new user selections have been made}
- fillListMsg = 13; {fill the list with choices to be made}
- getSelMsg = 14; {mark one or more choices as selected}
- selectMsg = 15; {a choice has actually been made}
- deselectMsg = 16; {a choice has been cancelled}
- terminateMsg = 17; {lets device package clean up}}
- buttonMsg = 19; {tells driver a button has been selected}
-
- The device package should always return noErr, except with select and deselect; with
- these messages, a result code other than noErr prevents selection or deselection from
- occurring. The device package must ignore any other messages in the range 0..127 and
- return noErr. If the message is selectMsg or deselectMsg, it may not call the List
- Manager.
-
- The caller parameter identifies the caller as the Chooser, with a value of 1. Values
- in the range 0..127 are reserved; values outside this range may be used by applications.
-
- For AppleTalk devices, the zoneName parameter is a pointer to a string of up to 32
- characters containing the name of the AppleTalk zone in which the devices can be
- found. If the Chooser is being used with the local zone and bit 24 of the Flags field
- of the 'PACK' –4096 resource is clear, the string value is '*'; otherwise it’s the
- actual zone name.
-
- The p1 parameter is a handle to a List Manager list of choices for a particular
- device; this device list must be filled by the device package in response to the
- fillListMsg message.
-
- Other details of the Chooser messages and their parameters are given below.
-
- »The NewSelMsg Parameter
-
- The Chooser sends the newSel message (instead of the select or deselect message) only
- to device packages that allow multiple selections, when the user changes the selection.
-
- The objName and p2 parameters are not used.
-
- »The FillListMsg Parameter
-
- When the Chooser sends the fillList message, the device package should fill a List
- Manager list filled with choices for a particular device; the p1 parameter is a
- handle to this list.
-
- The objName and p2 parameters are not used.
-
- »The GetSelMsg Parameter
-
- When the Chooser sends the getSel message the device package should mark one or more
- choices in the given list as currently selected, by a call to LSetSelect.
-
- The objName and p2 parameters are not used.
-
- »The SelectMsg Parameter
-
- The Chooser sends the select message whenever a particular choice has become selected,
- but only to device packages that do not allow multiple selections. The device package
- may not call the List Manager.
-
- If the device accepts fillList messages, objName is undefined. Otherwise, the objName
- parameter is a pointer to a string of up to 32 characters containing the name of the
- device.
-
- If the device accepts fillList messages, p2 gives the row number of the list that has
- become selected; otherwise (if the device is an AppleTalk device) p2 gives the AddrBlock
- value for the address of the AppleTalk device that has just become selected.
-
- »The DeselectMsg Parameter
-
- The Chooser sends the deselect message whenever a particular choice has become deselected,
- but only to device packages that do not allow multiple selections. The device package
- may not call the List Manager.
-
- If the device accepts fillList messages, objName is undefined. Otherwise, the objName
- parameter is a pointer to a string of up to 32 characters containing the name of the
- device.
-
- If the device accepts fillList messages, p2 gives the row number of the list that has
- become deselected; otherwise (if the device is an AppleTalk device) p2 gives the
- AddrBlock value for the address of the AppleTalk device that has just become deselected.
-
- »The TerminateMsg Parameter
-
- The Chooser sends the terminate message when the user selects a different device
- icon, closes the Chooser window, or changes zones. It allows the device package to
- perform cleanup tasks, if necessary. The device package should not dispose of the
- device list.
-
- The objName and p2 parameters are not used.
-
- »The ButtonMsg Parameter
-
- The Chooser sends the button message when a button in the Chooser display has been
- clicked.
-
- The low-order byte of the p2 parameter has a value of 1 if the left button has been
- clicked and 2 if the right button has been clicked.
-
- The objName parameter is not used.
-
- _______________________________________________________________________________
-
- »Operation of the Chooser
-
- When the Chooser is first selected from the desk accessory menu, it searches the
- system folder of the startup disk for device resource files—that is, resource files
- of type 'PRER', 'PRES', or 'RDEV'. For each one that it finds, it opens the file,
- fetches the device’s icon, fetches the flags long word from the device package, and
- closes the file. The Chooser then takes the following actions for each device, based
- on the information just retrieved:
-
- • It displays the device’s icon in the Chooser’s window.
- • If the device is an AppleTalk device and AppleTalk is not connected,
- the Chooser grays the device’s icon.
-
- When the user selects a device icon that is not grayed, the Chooser reopens the
- corresponding device resource file. It then does the following:
-
- • If the device is type 'PRER' or 'PRES', it sets the current
- printer type to that device.
-
- • It labels the device’s list box with the string in the resource
- 'STR ' with an ID of –4091.
-
- • If the device is a local printer, the Chooser fills its list box
- with the two icons for the printer port and modem port serial drivers.
- Later it will record the user’s choice in low memory and parameter RAM.
-
- • If the device accepts fillList messages, the Chooser calls the device
- package, which should fill column 0 of the list pointed to by p1 with
- the names (without length bytes) of all available devices in the zone.
-
- • If the device is an AppleTalk device that does not accept fillList
- messages, the Chooser initiates an asynchronous routine that interrogates
- the current AppleTalk zone for all devices of the type specified in the
- device’s resource 'STR ' –4096. The NBP retry interval and count are
- taken from the 'GNRL' resource –4096; the format of this resource
- consists one byte for the interval followed by another byte for the
- count. As responses arrive, the Chooser updates the list box.
-
- • To determine which list choices should be currently selected, the
- Chooser calls the device with the getSel message. The device code
- should respond by inspecting the list and setting the selected/unselected
- state of each entry. The Chooser may make this call frequently; for
- example, each time a new response to the AppleTalk zone interrogation
- arrives. Hence the device should alter only those entries that need
- changing. This procedure is not used with serial printers; for them,
- the Chooser just accesses low memory.
-
- • The Chooser checks the flag in the 'PACK' –4096 resource that indicates
- whether multiple devices can be active at once, and sets List Manager
- bits accordingly. Whenever the user selects or deselects a device, the
- Chooser will call the device package with the appropriate message (if
- it’s accepted). For packages that do not accept multiple active devices,
- this is the select or deselect message; otherwise it’s the newSel message.
- The device code should implement both mounting and unmounting the device,
- if appropriate, and recording the user’s selections on disk, preferably
- in the device resource file (which is the current resource file).
-
- When the Chooser is deactivated, it calls the UpdateResFile procedure on the device
- resource file and flushes the system startup volume.
-
- When the user chooses a different device type icon or closes the Chooser, the Chooser
- will call the device with the terminate message (if it’s accepted). This allows
- device packages to clean up, if necessary. After this check, the Chooser closes the
- device resource file (if the device is not the current printer) and flushes the
- system startup volume.
-
- _______________________________________________________________________________
-
- »Writing a Device Driver to Run Under Chooser
-
- The code section of a driver running under chooser is contained in the 'PACK'
- –4096 resource, as explained earlier. The driver structure remains as described
- earlier in this chapter.
-
- Device packages initially have no data space allocated. There are two ways to acquire
- data space for a device package:
-
- • Use the List Manager
- • Create a resource
-
- These options are discussed below.
-
- The best method is to call the List Manager. The Chooser uses column 0 of the device
- list to store the names displayed in the list box. If the device package currently in
- use does not accept fillList messages, column 1 stores the four-byte AppleTalk internet
- addresses of the entities in the list. Therefore, the device package can use column 1
- and higher (if it accepts fillList) or column 2 and higher to store data private to
- itself. The standard List Manager calls can be used to add these columns, place data
- in them, and retrieve data stored there.
-
- •••Refer to Technical Note #250:•••
-
- There are several restrictions on data storage in List Manager cells. The list is
- disposed whenever :
-
- • the user changes device types.
- • the user changes the current zone.
- • the device package does not accept fillList messages, and a new
- response to the AppleTalk zone interrogation arrives. The device
- package will be called with the getSel message immediately afterwards.
-
- When either of the first two situations occurs, the device package is called with the
- terminate message before the list is disposed.
-
- Another way to get storage space is to create a resource in the device’s file. This
- file is always the current resource file when the package is called; therefore it can
- issue GetResource calls to get a handle to its storage.
-
- It is important for most device packages to record which devices have been chosen. To
- do this, the recommended method is to create a resource in the resource file. This
- resource can be of any type; it fact, it’s advantageous to provide your own resource
- type so that no other program will try to access it. If you choose to use a standard
- resource type, you should use only resource IDs in the range –4080 to –4065.
-
-
- Note: The extensions to the Device Manager described in the following
- paragraphs were originally documented in Inside Macintosh, Volume V.
- As such, this information refers to the Macintosh SE and Macintosh II
- ROMs and System file version 4.1 and later.
-
- _______________________________________________________________________________
-
- »Chooser Changes
-
- Note: The extensions to the Device Manager described in the following
- paragraphs were originally documented in Inside Macintosh, Volume V.
- As such, this information refers to the Macintosh SE and Macintosh II
- ROMs and System file version 4.1 and later.
-
- Three new facilities for user-written device packages have been added to the Chooser:
-
- • In addition to specifying and setting their names, a device package
- can now position one or both buttons.
- • A device package can now supply a custom list definition for the
- device list. The custom list can include icons, pictures, or small
- icons next to the name.
- • Applications that do their own housekeeping can now bypass the
- warning message brought up whenever a different device is chosen.
-
- Figure 8 shows the new window displayed by the Chooser.
-
- •••Refer to Figure 8.•••
-
- Figure 8–The Chooser Window
-
- As described elsewhere in this chapter, the Chooser can also prompt the user for
- which AppleTalk network zone to communicate with. See Figure 9.
-
- •••Refer to Figure 9.•••
-
- Figure 9–The Chooser Displaying Zones
-
- »Buttons
-
- A device package can choose to have 0, 1, or 2 buttons, as determined by bits 27 and
- 26 in the flag field of the device ID. The two buttons are not the same. The button
- set by bit 27 is called the Left Button, and the button set by bit 26 the Right
- Button, because these are their default positions.
-
- The Left Button has a double border, and if it is highlighted (the title string is
- dark, not gray), then a Return, Enter, or double click are equivalent to clicking the
- button. The Left Button is highlighted only when one or more devices are selected in
- the device list. The Right Button has a single border, never dims its title, and can
- be activated only by clicking it.
-
- Buttons can be positioned by having a resource type 'nrct' with an ID of –4096 in
- the device file. The first word of the resource is the number of rectangles in the
- list, in this case two; the rest of the resource contains the rectangle definitions.
- The first rectangle is the Left Button, the second is the Right Button.
-
- Each rectangle definition is eight bytes long and contains the rectangle coordinates
- in the order [top, left, bottom, right] order. The default values are [112, 206, 132,
- 266] for the Left Button, and [112, 296, 132, 356] for the Right Button. Substituting
- 'nrct' values of [112, 251, 132, 311], for example, would center a single button.
-
- There’s an additional button-related change: in the ButtonMsg parameter, the low
- order byte of the P2 parameter has a value of 1 or 2 depending on whether the Left
- Button or Right Button was clicked. The high order word of P2 now contains modifier
- bits from the event.
- _______________________________________________________________________________
-
- »List Definition Procedure
-
- The Chooser uses the List Manager to produce and display the standard device list.
- The programmer can now supply a list definition procedure, which could, for example,
- include pictures or icons. The application should provide an
- 'LDEF' resource with an ID of –4096.
-
- Also, with Chooser 3.0 and above the device may use the refCon field of the device
- list for its own purposes. Remember that the list will be disposed of whenever the
- user changes device types or changes the current zone.
-
- Before the list is disposed of, the device package will be called with the terminate
- message.
-
- See the List Manager chapter for the mechanics of list construction and the list
- record data structure.
-
- »Page Setup
-
- The Chooser normally issues a warning message whenever a different printer type is
- selected:
-
- Be sure to choose Page Setup and confirm the settings so that
- the application can format documents correctly for the <printer>.
-
- Since some applications handle the page resetup correctly on their own, the Chooser
- now offers a way for applications to bypass the message.
-
- FUNCTION SetChooserAlert (f:BOOLEAN) : BOOLEAN;
-
- If f is true, the Chooser will put up the page setup alert; if f is false it won’t.
- SetChooserAlert returns the original alert state. The application should restore the
- original alert state when it exits.
-
- Assembly-language note: If the psAlert bit of the low-memory global
- HiliteMode is 0 then no page setup alert will be
- generated. Applications that set or clear this
- bit must be sure not to affect any other bits in
- the byte and to restore the bit as they leave.
-
- HiliteMode equ $938
- psAlert equ 6
- bclr #psAlert,HiliteMode
- bset #psAlert,HiliteMode
-
- »Device Package Function
-
- When the device package is called, the device file will be the current resource file,
- the Chooser’s window will be the current grafPort, and the System Folder of the
- current startup disk will be the default volume. The device package must preserve
- all of these.
-
- _______________________________________________________________________________
-
-
- æKY The…Startup…Process
- æC »THE STARTUP PROCESS DeviceManager
- _______________________________________________________________________________
-
- Note: The extensions to the Device Manager described in the following
- sections were originally documented in Inside Macintosh, Volume V.
- As such, this information refers to the Macintosh SE and Macintosh II
- ROMs and System file version 4.1 and later.
-
- The Macintosh II ROM searches for the startup device using an algorithm described in
- the Start Manager chapter. It will attempt to start from a NuBus card only when
- certain values are set in its parameter RAM. These values can be accessed by using
- Start Manager routines.
-
- When the Macintosh starts up from a card in a NuBus slot, it uses startup code found
- in an sResource in the configuration ROM on the card. Otherwise, the normal Macintosh
- startup process occurs. Configuration ROMs and sResources are described in the Slot
- Manager chapter and in the book “Designing Cards and Drivers for Macintosh II and
- Macintosh SE.”
-
- If parameter RAM specifies a valid sResource ID and slot, and if that sResource has
- an sBootRecord, it is used for startup. The ROM loads the slot startup code into
- memory and calls its entry point to execute it. For non-Macintosh operating systems
- that take over the machine, this code is either the operating system itself or a
- startup program. For instance, a traditional UNIX® startup process would bring in
- the secondary startup program, which prompts for a device name or filename to execute.
- The ROM would never receive control again.
-
- The sBootRecord code is first called early in the ROM-based startup sequence, before
- any access to the internal drive. It is passed an seBlock pointed to by register A0.
- If a non-Macintosh operating system is being installed, the sBootRecord can pass
- control to it. In this case, control never returns to the normal start sequence in
- the Macintosh ROM.
-
- When the Macintosh operating system is started up, the sBootRecord is called twice.
- The first time, when the value of seBootState is 0, the startup code tries to load
- and open at least one driver for the card-based device and install it in the disk
- drive queue. It returns the refnum of the driver. That driver becomes the initial
- one used to install the Macintosh operating system. During the second call to the
- sBootRecord (when the value of seBootState is 1), which happens after system patches
- have been installed but before 'INIT' resources have been executed, the sBootRec must
- open any remaining drivers for devices on the card.
-
- The sBootRecord can use the HOpen call to open the driver and install it into the
- unit table. The HOpen call will either fetch the driver from the sDriver directory,
- or call the sLoadDriver record if one exists. In any case, the driver’s open code
- must install the driver into the drive queue. This process is discussed in more
- detail in the Card Firmware chapter of the book “Designing Cards and Drivers for
- Macintosh II and Macintosh SE.”
-
- _______________________________________________________________________________
-
- »Automatic Driver Installation
-
- During the startup process the system installs the default video and startup drivers,
- as described in the Start Manager chapter. Immediately prior to installing the
- 'INIT' resources, the system searches the NuBus slots looking for other device drivers
- to install. The sRsrcDir data structure in each
- card’s configuration ROM describes all devices on that card. For each device there
- is a sRsrcList structure which contains the resource name (sRsrcName) and the offset
- to a table of drivers. These structures are described in the Slot Manager chapter.
-
- For each sResource, the search for drivers during startup takes place in the following
- steps:
-
- 1. The operating system looks for an sRsrc_Flags field in the sResource list.
-
- 2. If no sRsrc_Flags field exists, or if an sRsrc_Flags field exists and
- the field’s fOpenAtStart bit is set to 1, the operating system searches
- for a driver, as described below in steps 3 and 4. If the value of
- fOpenAtStart is 0, the operating system does not search for a driver;
- it goes on to the next sResource.
-
- 3. The system searches the sResource list for a driver load record
- (sRsrc_LoadRec)— a routine designed to copy a driver into the Macintosh
- system heap. If such a routine exists, the system copies it from the
- card’s ROM to the heap and executes it. The system passes this routine
- a pointer in A0 to an seBlock; on exit, the routine must return a handle
- in the seResult field of the same seBlock to the driver it has loaded.
- If the value of the seStatus field is 0, the system then installs the
- new driver.
-
- 4. If there is no driver load record, the system searches the sResource
- list for a driver directory entry (sRsrc_DrvrDir). If there is such
- an entry and the directory contains a driver of the type sMacOS68000
- or sMacOS68020, the system reads the driver from the card’s ROM and
- installs it in the Macintosh system heap.
-
- To install a driver, the Macintosh II ROM first loads it into the system heap and
- locks it if the dNeedsLock bit in the driver flags (drvrFlags) word is set. It then
- installs the driver with a DrvrInstall system call and initializes it with an Open
- call. If the driver returns an error from the Open call, it is marked closed, the
- refNum field is cleared in the ioParameter block, and the driver is unlocked. Note
- that this procedure guarantees that driver initialization code will be executed
- before the system starts executing applications.
-
- The video driver used at the beginning of system startup (the one that makes the
- “happy Macintosh” appear) must be taken from a video card’s configuration ROM because
- the System file is not yet accessible. If a system contains multiple video cards,
- the one used first is determined by parameter RAM or, by default, by selecting the
- lowest slot number. To override this initial driver, the user must install an 'INIT'
- 31 resource that explicitly closes the driver from the configuration ROM and loads a
- new driver from a file.
-
- The unit table data structure has been extended from 48 devices to 64 to accommodate
- installing slot devices. If more than 64 entries are needed, the table automatically
- expands up to a maximum of 128 entries.
-
- When a driver serves a device that is plugged into a NuBus slot, it needs to know the
- slot number, the sResource ID number and the ExtDevID number. These numbers are
- discussed in the Slot Manager chapter. The Slot Manager provides values for five new
- entries on the end of the Device Control Entry (DCE) data structure for each sResource.
- These new entries are
-
- • a byte containing the slot number (dCtlSlot)
- • a byte containing the RsrcDir ID number for the sResource (dCtlSlotID)
- • a pointer for the driver to use for the device base address (dCtlDevBase)
- • a reserved field for future use
- • a byte containing the external device ID (dCtlExtDev)
-
- The Device Control Entry now looks like this:
-
- AuxDCE = PACKED RECORD
- dCtlDriver: Ptr; {ptr to ROM or handle to RAM driver}
- dCtlFlags: INTEGER; {flags}
- dCtlQHdr: QHdr; {driver's i/o queue}
- dCtlPosition: LONGINT; {byte pos used by read and write calls}
- dCtlStorage: Handle; {hndl to RAM drivers private storage}
- dCtlRefNum: INTEGER; {driver's reference number}
- dCtlCurTicks: LONGINT; {counter for timing system task calls}
- dCtlWindow: Ptr; {ptr to driver's window if any}
- dCtlDelay: INTEGER; {number of ticks btwn sysTask calls}
- dCtlEMask: INTEGER; {desk acessory event mask}
- dCtlMenu: INTEGER; {menu ID of menu associated with driver}
- dCtlSlot: Byte; {slot}
- dCtlSlotId: Byte; {slot ID}
- dCtlDevBase: LONGINT; {base address of card for driver}
- reserved: LONGINT; {reserved; should be 0}
- dCtlExtDev: Byte; {external device ID}
- fillByte: Byte; {reserved}
- END; {SlotDCE}
- AuxDCEPtr = ^AuxDCE;
- AuxDCEHandle = ^AuxDCEPtr;
-
- All Device Control Entries are set before the driver’s Open routine is called.
-
- Use of the base address pointer dCtlDevBase in the DCE is optional. On a card with
- multiple instances of the same device, the driver can use this pointer to distinguish
- between devices. Because the DCE address is passed to the driver on every call from
- the Device Manager, the presence of this pointer in the DCE simplifies location of
- the correct device. This pointer is the address of the base of the card’s slot space
- plus an optional offset obtained from the MinorBaseOS field of the sResource. This
- field frees the driver writer from the necessity of locating the hardware for simple
- slot devices. The system makes no other references to it.
-
- _______________________________________________________________________________
-
-
- æKY Opening…Slot…Devices
- æC »OPENING SLOT DEVICES DeviceManager
- _______________________________________________________________________________
-
- The low-level PBOpen routine has been extended to let you open devices in NuBus
- slots. A new call has been defined: OpenSlot is the equivalent of PBOpen except that
- it sets the IMMED bit, which signals an extended parameter block.
-
- FUNCTION OpenSlot(paramBlock: paramBlkPtr; aSync: BOOLEAN) : OsErr;
-
- If the slot sResource serves a single device (for example, a video device), clear all
- the bits of the ioFlags field and use the following parameter block:
-
- Parameter block
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 18 ioNamePtr pointer
- <-- 22 ioRefNum word
- --> 27 ioPermssn byte
-
- --> 28 ioMix pointer
- --> 32 ioFlags word
- --> 34 ioSlot byte
- --> 35 ioId byte
-
- In the extension fields, ioMix is a pointer reserved for use by the driver open
- routine. The ioSlot parameter contains the slot number of the device being opened,
- in the range 9..$E; if a built-in device is being opened, ioSlot must be 0. The ioId
- parameter contains the sResource ID. Slot numbers and sResources are discussed in
- the Slot Manager.
-
- If the slot sResource serves more than one device (for example, a chain of disk
- drives), set the fMulti bit in the ioFlags field (clearing all other flags bits to 0)
- and use the following parameter block:
-
- Parameter block
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 18 ioNamePtr pointer
- <-- 22 ioRefNum word
- --> 27 ioPermssn byte
-
- --> 28 ioMix pointer
- --> 32 ioFlags word
- --> 34 ioSEBlkPtr pointer
-
- Here the new parameter ioSEBlkPtr is a pointer to an external parameter block
- (described in the Slot Manager chapter) that is customized for the devices installed
- in the slot. The pointer value is passed to the driver.
-
- _______________________________________________________________________________
-
-
- æKY Slot…Device…Interrupts
- æC »SLOT DEVICE INTERRUPTS DeviceManager
- _______________________________________________________________________________
-
- Slot interrupts enter the system by way of the Macintosh II VIA2 chip, which contains
- an 8-bit register that has a bit for each slot. This means that there is effectively
- one interrupt line per card. You can tell almost instantly which card requested the
- interrupt, but not which device on the card. To locate the interrupt to a device,
- the Slot Manager provides the polling procedure described below.
-
- The Device Manager maintains an interrupt queue for each slot. The queue elements
- are ordered by priority and contain pointers to polling routines. Upon receipt of a
- slot interrupt the Device Manager goes through the slot’s interrupt queue, calling
- each polling routine, until it gets an indication that the interrupt has been satisfied.
- If no such indication occurs, a system error dialog is displayed.
-
- The format for a slot interrupt queue element is the following:
-
- SQLink EQU 0 ;link to next element (pointer)
- SQType EQU 4 ;queue type ID for validity (word)
- SQPrio EQU 6 ;priority (low byte of word)
- SQAddr EQU 8 ;interrupt service routine (pointer)
- SQParm EQU 12 ;optional A1 parameter (long)
-
- The SQLink field points to the next queue entry; it is maintained by the system. The
- SQType field identifies the structure as an element of a slot interrupt queue. It
- should be set to SIQType. The SQPrio field is an unsigned byte that determines the
- order in which slots are polled and routines are called. Higher value routines are
- called sooner. Priority values 200–255 are reserved for Apple devices. The SQAddr
- field points to the interrupt polling routine.
-
- •••Refer to Technical Notes #221 & #257:•••
-
- The SQParm field is a value which is loaded into A1 before calling an interrupt
- service routine. This could be a handle to the driver’s DCE, for example.
-
- _______________________________________________________________________________
-
-
- æKY New…Routines
- æC »NEW ROUTINES DeviceManager
- _______________________________________________________________________________
-
- The Device Manager provides two new routines to implement the interrupt queue process
- just described: SIntInstall and SIntRemove. They are described below.
-
- FUNCTION SIntInstall(sIntQElemPtr: SQElemPtr; theSlot: INTEGER) : OsErr;
-
- Trap macro _SIntInstall
- On entry D0: slot number (word)
- A0: address of slot queue element
- On exit D0: error code
-
- SIntInstall adds a new element (pointed to by sIntQElemPtr) to the interrupt queue
- for the slot whose number is given in theSlot. As explained in the Slot Manager
- chapter, slots are numbered from 9 to $E.
-
- Assembly-language note: From assembly language, this routine has the
- following calling sequence (assuming A0 points
- to a slot queue element):
-
- LEA PollRoutine,A1 ;get routine address
- MOVE.L A1,SQAddr(A0) ;set address
- MOVE.W Prio,SQPrio(A0) ;set priority
- MOVE.L A1Parm,SQParm(A0) ;save A1 parameter
- MOVE.W Slot,D0 ;set slot number
- _SIntInstall ;do installation
-
- This code causes the routine at label PollRoutine to
- be called as a result of an interrupt from the
- specified slot (9..$E). The Device Manager will
- poll the slot which has the highest priority first if
- two or more slots request an interrupt simultaneously.
-
- FUNCTION SIntRemove(sIntQElemPtr: SQElemPtr; theSlot: INTEGER) : OsErr;
-
- Trap macro _SIntRemove
- On entry D0: slot number (word)
- A0: address of slot queue element
- On exit D0: error code
-
- SIntRemove removes an element (pointed to by sIntQElemPtr) from the interrupt queue
- for the slot whose number is given in theSlot. As explained in the Slot Manager
- chapter, slots are numbered from 9 to $E.
-
- Assembly-language note: From assembly language, this routine has the
- following calling sequence (assuming A0 points
- to a slot queue element):
-
- LEA MySQEl,A0 ;pointer to queue element
- _SIntRemove ;remove it
-
- This routine lets you remove an interrupt handler
- from the system without causing a crash.
-
- Your driver polling routine will be called with the following assembly-language
- code:
-
- MOVE.L A1Parm,A1 ;load A1 Parameter
- JSR PollRoutine ;call polling routine
-
- Your polling routine should preserve the contents of all registers except A1 and D0.
- It should return to the Device Manager with an RTS instruction. D0 should be set to
- zero to indicate that the polling routine did not service the interrupt, or nonzero
- to indicate the interrupt has been serviced. The polling routine should not set the
- processor priority below 2, and should return with the processor priority equal to 2.
- The Device Manager resets the VIA2 int flag and executes an RTE to the interrrupted
- task when a polling routine indicates that the interrupt is satisfied; otherwise, it
- calls the next lower-priority polling routine for that slot. If none exists, a
- system error results.
-
- _______________________________________________________________________________
-
-
- æKY Summary…of…the…Device…Manager
- æC »SUMMARY OF THE DEVICE MANAGER DeviceManager
- _______________________________________________________________________________
-
- Constants
-
- CONST
-
- { Values for requesting read/write access }
-
- fsCurPerm = 0; {whatever is currently allowed}
- fsRdPerm = 1; {request to read only}
- fsWrPerm = 2; {request to write only}
- fsRdWrPerm = 3; {request to read and write}
-
- { Positioning modes }
-
- fsAtMark = 0; {at current position}
- fsFromStart = 1; {offset relative to beginning of medium}
- fsFromMark = 3; {offset relative to current position}
- rdVerify = 64; {add to above for read-verify}
-
- [Volume IV additions]
-
- {Chooser message values}
-
- newSelMsg = 12; {new user selections have been made}
- fillListMsg = 13; {fill the list with choices to be made}
- getSelMsg = 14; {mark one or more choices as selected}
- selectMsg = 15; {a choice has actually been made}
- deselectMsg = 16; {a choice has been cancelled}
- terminateMsg = 17; {lets device package clean up}
- buttonMsg = 19; {tells driver a button has been selected}
-
- {caller values}
-
- chooserID = 1; {caller value for the Chooser}
-
- _______________________________________________________________________________
-
- Data Types
-
- TYPE
- ParamBlkType = (ioParam,fileParam,volumeParam,cntrlParam);
-
- ParamBlockRec = RECORD
- qLink: QElemPtr; {next queue entry}
- qType: INTEGER; {queue type}
- ioTrap: INTEGER; {routine trap}
- ioCmdAddr: Ptr; {routine address}
- ioCompletion: ProcPtr; {completion routine}
- ioResult: OSErr; {result code}
- ioNamePtr: StringPtr; {driver name}
- ioVRefNum: INTEGER; {volume reference or }
- { drive number}
- CASE ParamBlkType OF
- ioParam:
- (ioRefNum: INTEGER; {driver reference number}
- ioVersNum: SignedByte; {not used}
- ioPermssn: SignedByte; {read/write permission}
- ioMisc: Ptr; {not used}
- ioBuffer: Ptr; {pointer to data buffer}
- ioReqCount: LONGINT; {requested number of bytes}
- ioActCount: LONGINT; {actual number of bytes}
- ioPosMode: INTEGER; {positioning mode}
- ioPosOffset: LONGINT); {positioning offset}
- fileParam:
- . . . {used by the File Manager}
- volumeParam:
- . . . {used by the File Manager}
- cntrlParam:
- (ioCRefNum: INTEGER; {driver reference number}
- csCode: INTEGER; {type of Control or Status call}
- csParam: ARRAY[0..10] OF INTEGER); {control or status }
- { information}
- END;
-
- DCtlHandle = ^DCtlPtr;
- DCtlPtr = ^DCtlEntry;
- DCtlEntry = RECORD
- dCtlDriver: Ptr; {pointer to ROM driver or }
- { handle to RAM driver}
- dCtlFlags: INTEGER; {flags}
- dCtlQHdr: QHdr; {driver I/O queue header}
- dCtlPosition: LONGINT; {byte position used by Read }
- { and Write calls}
- dCtlStorage: Handle; {handle to RAM driver's }
- { private storage}
- dCtlRefNum: INTEGER; {driver reference number}
- dCtlCurTicks: LONGINT; {used internally}
- dCtlWindow: WindowPtr; {pointer to driver's window}
- dCtlDelay: INTEGER; {number of ticks between }
- { periodic actions}
- dCtlEMask: INTEGER; {desk accessory event mask}
- dCtlMenu: INTEGER {menu ID of menu associated
- { with driver}
- END;
-
- _______________________________________________________________________________
-
- High-Level Routines [Not in ROM]
-
- FUNCTION OpenDriver (name: Str255; VAR refNum: INTEGER) : OSErr;
- FUNCTION CloseDriver (refNum: INTEGER) : OSErr;
- FUNCTION FSRead (refNum: INTEGER; VAR count: LONGINT;
- buffPtr: Ptr) : OSErr;
- FUNCTION FSWrite (refNum: INTEGER; VAR count: LONGINT;
- buffPtr: Ptr) : OSErr;
- FUNCTION Control (refNum: INTEGER; csCode: INTEGER;
- csParamPtr: Ptr) : OSErr;
- FUNCTION Status (refNum: INTEGER; csCode: INTEGER;
- csParamPtr: Ptr) : OSErr;
- FUNCTION KillIO (refNum: INTEGER) : OSErr;
-
- [Volume IV addition]
-
- FUNCTION Device (message,caller: INTEGER; objName,zoneName: StringPtr;
- p1,p2: LONGINT) : OSErr;
-
- [Volume V additions]
-
- FUNCTION OpenSlot (paramBlock: paramBlkPtr; aSync: BOOLEAN) : OsErr;
- FUNCTION SIntInstall (sIntQElemPtr: SQElemPtr; theSlot: INTEGER ) : OsErr;
- FUNCTION SIntRemove (sIntQElemPtr: SQElemPtr; theSlot: INTEGER) : OsErr;
-
- _______________________________________________________________________________
-
- Low-Level Routines
-
- FUNCTION PBOpen (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 18 ioNamePtr pointer
- <-- 24 ioRefNum word
- --> 27 ioPermssn byte
-
- FUNCTION PBClose (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 24 ioRefNum word
-
- FUNCTION PBRead (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 22 ioVRefNum word
- --> 24 ioRefNum word
- --> 32 ioBuffer pointer
- --> 36 ioReqCount long word
- <-- 40 ioActCount long word
- --> 44 ioPosMode word
- <-> 46 ioPosOffset long word
-
- FUNCTION PBWrite (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 22 ioVRefNum word
- --> 24 ioRefNum word
- --> 32 ioBuffer pointer
- --> 36 ioReqCount long word
- <-- 40 ioActCount long word
- --> 44 ioPosMode word
- <-> 46 ioPosOffset long word
-
- FUNCTION PBControl (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 22 ioVRefNum word
- --> 24 ioRefNum word
- --> 26 csCode word
- --> 28 csParam record
-
- FUNCTION PBStatus (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 22 ioVRefNum word
- --> 24 ioRefNum word
- --> 26 csCode word
- <-- 28 csParam record
-
- FUNCTION PBKillIO (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 24 ioRefNum word
-
- _______________________________________________________________________________
-
- Accessing a Driver’s Device Control Entry
-
- FUNCTION GetDCtlEntry (refNum: INTEGER) : DCtlHandle; [Not in ROM]
-
- _______________________________________________________________________________
-
- Result Codes
-
- Name Value Meaning
-
- abortErr –27 I/O request aborted by KillIO
- badUnitErr –21 Driver reference number doesn’t match unit table
- controlErr –17 Driver can’t respond to this Control call
- dInstErr –26 Couldn’t find driver in resource file
- dRemovErr –25 Attempt to remove an open driver
- noErr 0 No error
- notOpenErr –28 Driver isn’t open
- openErr –23 Requested read/write permission doesn’t match
- driver’s open permission
- readErr –19 Driver can’t respond to Read calls
- statusErr –18 Driver can’t respond to this Status call
- unitEmptyErr –22 Driver reference number specifies NIL handle in unit table
- writErr –20 Driver can’t respond to Write calls
-
- _______________________________________________________________________________
-
- Assembly-Language Information
-
- Constants
-
- ; Flags in trap words
-
- asnycTrpBit .EQU 10 ;set for an asynchronous call
- noQueueBit .EQU 9 ;set for immediate execution
-
- ; Values for requesting read/write access
-
- fsCurPerm .EQU 0 ;whatever is currently allowed
- fsRdPerm .EQU 1 ;request to read only
- fsWrPerm .EQU 2 ;request to write only
- fsRdWrPerm .EQU 3 ;request to read and write
-
- ; Positioning modes
-
- fsAtMark .EQU 0 ;at current position
- fsFromStart .EQU 1 ;offset relative to beginning of medium
- fsFromMark .EQU 3 ;offset relative to current position
- rdVerify .EQU 64 ;add to above for read-verify
-
- ; Driver flags
-
- dReadEnable .EQU 0 ;set if driver can respond to Read calls
- dWritEnable .EQU 1 ;set if driver can respond to Write calls
- dCtlEnable .EQU 2 ;set if driver can respond to Control calls
- dStatEnable .EQU 3 ;set if driver can respond to Status calls
- dNeedGoodBye .EQU 4 ;set if driver needs to be called before the
- ; application heap is reinitialized
- dNeedTime .EQU 5 ;set if driver needs time for performing a
- ; periodic action
- dNeedLock .EQU 6 ;set if driver will be locked in memory as
- ; soon as it's opened (always set for ROM drivers)
-
- ; Device control entry flags
-
- dOpened .EQU 5 ;set if driver is open
- dRAMBased .EQU 6 ;set if driver is RAM-based
- drvrActive .EQU 7 ;set if driver is currently executing
-
- ; csCode values for driver control routine
-
- accRun .EQU 65 ;take the periodic action, if any, for this driver
- goodBye .EQU –1 ;heap will be reinitialized, clean up if necessary
- killCode .EQU 1 ;handle the KillIO call
-
- ; Low-order byte of Device Manager traps
-
- aRdCmd .EQU 2 ;Read call (trap $A002)
- aWrCmd .EQU 3 ;Write call (trap $A003)
-
- ; Offsets from SCC base addresses
-
- aData .EQU 6 ;channel A data in or out
- aCtl .EQU 2 ;channel A control
- bData .EQU 4 ;channel B data in or out
- bCtl .EQU 0 ;channel B control
-
- [Volume IV additions]
-
- ; Chooser message values
-
- newSel .EQU 12 ;new user selections have been made
- fillList .EQU 13 ;fill the list with choices to be made
- getSel .EQU 14 ;mark one or more choices as selected
- select .EQU 15 ;a choice has actually been made
- deselect .EQU 16 ;a choice has been cancelled
- terminate .EQU 17 ;lets device package clean up
- button .EQU 19 ;tells driver a button has been selected
-
- ; Caller values
-
- chooserID .EQU 1 ;caller value for the Chooser
-
- [Volume V additions]
-
- ; Slot Queue Element
-
- SQLink EQU 0 ;link to next element (pointer)
- SQType EQU 4 ;queue type ID for validity (word)
- SQPrio EQU 6 ;priority (low byte of word)
- SQAddr EQU 8 ;interrupt service routine (pointer)
- SQParm EQU 12 ;optional A1 parameter (long)
-
- SIQType EQU 6 ;slot interrupt queue element type
-
- Standard Parameter Block Data Structure
-
- qLink Pointer to next queue entry
- qType Queue type (word)
- ioTrap Routine trap (word)
- ioCmdAddr Routine address
- ioCompletion Address of completion routine
- ioResult Result code (word)
- ioVNPtr Pointer to driver name (preceded by length byte)
- ioVRefNum Volume reference number (word)
- ioDrvNum Drive number (word)
-
- Control and Status Parameter Block Data Structure
-
- ioRefNum Driver reference number (word)
- csCode Type of Control or Status call (word)
- csParam Parameters for Control or Status call (22 bytes)
-
- I/O Parameter Block Data Structure
-
- ioRefNum Driver reference number (word)
- ioPermssn Open permission (byte)
- ioBuffer Pointer to data buffer
- ioReqCount Requested number of bytes (long)
- ioActCount Actual number of bytes (long)
- ioPosMode Positioning mode (word)
- ioPosOffset Positioning offset (long)
-
- Device Driver Data Structure
-
- drvrFlags Flags (word)
- drvrDelay Number of ticks between periodic actions (word)
- drvrEMask Desk accessory event mask (word)
- drvrMenu Menu ID of menu associated with driver (word)
- drvrOpen Offset to open routine (word)
- drvrPrime Offset to prime routine (word)
- drvrCtl Offset to control routine (word)
- drvrStatus Offset to status routine (word)
- drvrClose Offset to close routine (word)
- drvrName Driver name (preceded by length byte)
-
- Device Control Entry Data Structure
-
- dCtlDriver Pointer to ROM driver or handle to RAM driver
- dCtlFlags Flags (word)
- dCtlQueue Queue flags: low-order byte is driver’s version number (word)
- dCtlQHead Pointer to first entry in driver’s I/O queue
- dCtlQTail Pointer to last entry in driver’s I/O queue
- dCtlPosition Byte position used by Read and Write calls (long)
- dCtlStorage Handle to RAM driver’s private storage
- dCtlRefNum Driver’s reference number (word)
- dCtlWindow Pointer to driver’s window
- dCtlDelay Number of ticks between periodic actions (word)
- dCtlEMask Desk accessory event mask (word)
- dCtlMenu Menu ID of menu associated with driver (word)
-
- Structure of Primary Interrupt Vector Table
-
- autoInt1 Vector to level-1 interrupt handler
- autoInt2 Vector to level-2 interrupt handler
- autoInt3 Vector to level-3 interrupt handler
- autoInt4 Vector to level-4 interrupt handler
- autoInt5 Vector to level-5 interrupt handler
- autoInt6 Vector to level-6 interrupt handler
- autoInt7 Vector to level-7 interrupt handler
-
- [Volume IV additions]
-
- Device Package Data Structure
-
- Byte Value
-
- 0 BRA.S to offset $10
- 2 Device ID (word)
- 4 'PACK' (long word)
- 8 $F000 (–4096)
- A Version (word)
- C Flags (long word)
- 10 Start of driver code
-
- [Volume V additions]
-
- Device Control Entry Data Structure
-
- dCtlDriver Pointer to ROM driver or handle to RAM driver
- dCtlFlags Flags (word)
- dCtlQueue Queue flags: low-order byte is driver’s version number (word)
- dCtlQHead Pointer to first entry in driver’s I/O queue
- dCtlQTail Pointer to last entry in driver’s I/O queue
- dCtlPosition Byte position used by Read and Write calls (long)
- dCtlStorage Handle to RAM driver’s private storage
- dCtlRefNum Driver’s reference number (word)
- dCtlWindow Pointer to driver’s window
- dCtlDelay Number of ticks between periodic actions (word)
- dCtlEMask Desk accessory event mask (word)
- dCtlMenu Menu ID of menu associated with driver (word)
- dCtlSlot Slot number (byte)
- dCtlSlotID Resource directory ID number for sResource (byte)
- dCtlDevBase Device base address (pointer)
- reserved Longint reserved for future use (should be 0)
- dCtlExtDev External device ID (byte)
-
- OpenSlot Parameter Blocks
-
- If fMulti bit in ioFlags = 0:
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 18 ioNamePtr pointer
- <-- 22 ioRefNum word
- --> 27 ioPermssn byte
-
- --> 28 ioMix pointer
- --> 32 ioFlags word
- --> 34 ioSlot byte
- --> 35 ioId byte
-
- If fMulti bit in ioFlags = 1:
- --> 12 ioCompletion pointer
- <-- 16 ioResult word
- --> 18 ioNamePtr pointer
- <-- 22 ioRefNum word
- --> 26 ioPermssn byte
-
- --> 28 ioMix pointer
- --> 32 ioFlags word
- --> 34 ioSEBlkPtr pointer
-
- Macro Names
-
- Pascal name Macro name
-
- PBRead _Read
- PBWrite _Write
- PBControl _Control
- PBStatus _Status
- PBKillIO _KillIO
-
- Volume V additions
-
- sIntInstall _sIntInstall
- sIntRemove _sIntRemove
-
- _______________________________________________________________________________
-
- Routines for Writing Drivers
-
- Routine Jump vector On entry On exit
-
- Fetch JFetch A1: ptr to device D0: character fetched; bit 15=1
- control entry if last character in buffer
- Stash JStash A1: ptr to device D0: bit 15=1 if last character
- control entry requested
- D0: character to stash
- IODone JIODone A1: ptr to device
- control entry
- D0: result code (word)
-
- Variables
-
- UTableBase Base address of unit table
- JFetch Jump vector for Fetch function
- JStash Jump vector for Stash function
- JIODone Jump vector for IODone function
- Lvl1DT Level-1 secondary interrupt vector table (32 bytes)
- Lvl2DT Level-2 secondary interrupt vector table (32 bytes)
- VIA VIA base address
- ExtStsDT External/status interrupt vector table (16 bytes)
- SCCWr SCC write base address
- SCCRd SCC read base address
-
- Further Reference:
- _______________________________________________________________________________
- Resource Manager
- Desk Manager
- File Manager
- OS Utilities
- Start Manager
- Slot Manager
- List Manager Package
- Disk Driver
- Serial Drivers
- Technical Note #36, Drive Queue Elements
- Technical Note #56, Break/CTS Device Driver Event Structure
- Technical Note #71, Finding Drivers in the Unit Table
- Technical Note #108, AddDrive, DrvrInstall and DrvrRemove
- Technical Note #187, Don’t Look at ioPosOffset
- Technical Note #197, Chooser Enhancements
- Technical Note #208, Setting and Restoring A5
- Technical Note #221, NuBus Interrupt Latency
- Technical Note #250, AppleTalk Phase 2 on the Macintosh
- Technical Note #257, Slot Interrupt Prio-Technics
- Q & A Stack
- “Macintosh Family Hardware Reference”
- “Designing Cards and Drivers for the Macintosh II and Macintosh SE”
-
- æKY DialogManager
- æC
- THE DIALOG MANAGER
- _______________________________________________________________________________
-
- About…The…DialogManager…Chapter
- About…the…Dialog…Manager
- Dialog…and…Alert…Windows
- Dialogs…Alerts…and…Resources
- Color…Alert…and…Dialog…Resources
- Item…Lists…in…Memory
- Color…Dialog…Item…Lists
- Using…Color…Dialogs…and…Alerts
- Dialog…Records
- Alerts
- Using…the…Dialog…Manager
- Dialog…Manager…Routines
- Modifying…Templates…in…Memory
- Formats…of…Resources…for…Dialogs…and…Alerts
- Summary…of…the…Dialog…Manager
- _______________________________________________________________________________
-
-
-
- æKY About…The…DialogManager…Chapter
- æC »ABOUT THIS CHAPTER DialogManager
- _______________________________________________________________________________
-
- This chapter describes the Dialog Manager, the part of the Toolbox that allows you to
- implement dialog boxes and the alert mechanism, two means of communication between
- the application and the end user.
-
- This chapter also describes the enhancements to the Dialog Manager for the Macintosh
- II. A new Dialog Manager routine now provides color dialog and item support. The new
- resource types 'dctb', 'actb', and 'ictb', which are auxiliary data structures to
- 'DITL', 'ALRT', and 'DLOG', allow color dialog boxes and alert boxes to be stored as
- resources. If the 'ALRT', 'DLOG', or
- 'DITL' resources are missing, the Dialog Manager will gracefully return from the
- Alert, NoteAlert, CautionAlert, StopAlert, and GetNewDialog calls.
-
- You should already be familiar with:
-
- • resources, as discussed in the Resource Manager chapter
- • the basic concepts and structures behind QuickDraw, particularly
- rectangles, grafPorts, and pictures
- • the Toolbox Event Manager, the Window Manager, and the Control Manager
- • TextEdit, to understand editing text in dialog boxes
-
- _______________________________________________________________________________
-
-
- æKY About…the…Dialog…Manager
- æC »ABOUT THE DIALOG MANAGER DialogManager
- _______________________________________________________________________________
-
- The Dialog Manager is a tool for handling dialogs and alerts in a way that’s consistent
- with the Macintosh User Interface Guidelines.
- A dialog box appears on the screen when a Macintosh application needs more information
- to carry out a command. As shown in Figure 1, it typically resembles a form on which
- the user checks boxes and fills in blanks.
-
- •••Refer to Figure 1.•••
-
- Figure 1–A Typical Dialog Box
-
- By convention, a dialog box comes up slightly below the menu bar, is somewhat narrower
- than the screen, and is centered between the left and right edges of the screen. It
- may contain any or all of the following:
-
- • informative or instructional text
- • rectangles in which text may be entered (initially blank or
- containing default text that can be edited)
- • controls of any kind
- • graphics (icons or QuickDraw pictures)
- • anything else, as defined by the application
-
- The user provides the necessary information in the dialog box, such as by entering
- text or clicking a check box. There’s usually a button labeled “OK” to tell the
- application to accept the information provided and perform the command, and a button
- labeled “Cancel” to cancel the command as though it had never been given (retracting
- all actions since its invocation). Some dialog boxes may use a more descriptive word
- than “OK”; for simplicity, this chapter will still refer to the button as the “OK
- button”. There may even be more than one button that will perform the command, each
- in a different way.
-
- Most dialog boxes require the user to respond before doing anything else. Clicking a
- button to perform or cancel the command makes the box go away; clicking outside the
- dialog box only causes a beep from the Macintosh’s speaker. This type is called a
- modal dialog box because it puts the user in the state or “mode” of being able to
- work only inside the dialog box. A modal dialog box usually has the same general
- appearance as shown in Figure 1 above. One of the buttons in the dialog box may be
- outlined boldly. Pressing the Return key or the Enter key has the same effect as
- clicking the outlined button or, if none, the OK button; the particular button whose
- effect occurs is called the dialog’s default button and is the preferred (“safest”)
- button to use in the current situation. If there’s no boldly outlined or OK button,
- pressing Return or Enter will by convention have no effect.
-
- Other dialog boxes do not require the user to respond before doing anything else;
- these are called modeless dialog boxes (see Figure 2). The user can, for example, do
- work in document windows on the desktop before clicking a button in the dialog box,
- and modeless dialog boxes can be set up to respond to the standard editing commands
- in the Edit menu. Clicking a button in a modeless dialog box will not make the box go
- away: The box will stay around so that the user can perform the command again. A
- Cancel button, if present, will simply stop the action currently being performed by
- the command; this would be useful for long printing or searching operations, for
- example.
-
- •••Refer to Figure 2.•••
-
- Figure 2–A Modeless Dialog Box
-
- As shown in Figure 2, a modeless dialog box looks like a document window. It can be
- moved, made inactive and active again, or closed like any document window. When
- you’re done with the command and want the box to go away, you can click its close box
- or choose Close from the File menu when it’s the active window.
-
- Dialog boxes may in fact require no response at all. For example, while an application
- is performing a time-consuming process, it can display a dialog box that contains
- only a message telling what it’s doing; then, when the process is complete, it can
- simply remove the dialog box.
-
- The alert mechanism provides applications with a means of reporting errors or giving
- warnings. An alert box is similar to a modal dialog box, but it appears only when
- something has gone wrong or must be brought to the user’s attention. Its conventional
- placement is slightly farther below the menu bar than a dialog box. To assist the
- user who isn’t sure how to proceed when an alert box appears, the preferred button to
- use in the current situation is outlined boldly so it stands out from the other
- buttons in the alert box (see Figure 3). The outlined button is also the alert’s
- default button; if the user presses the Return key or the Enter key, the effect is
- the same as clicking this button.
-
- •••Refer to Figure 3.•••
-
- Figure 3–A Typical Alert Box
-
- There are three standard kinds of alerts—Stop, Note, and Caution—each indicated by a
- particular icon in the top left corner of the alert box. Figure 3 illustrates a
- Caution alert. The icons identifying Stop and Note alerts are similar; instead of a
- question mark, they show an exclamation point and an asterisk, respectively. Other
- alerts can have anything in the the top left corner, including blank space if desired.
-
- The alert mechanism also provides another type of signal: Sound from the Macintosh’s
- speaker. The application can base its response on the number of consecutive times an
- alert occurs; the first time, it might simply beep, and thereafter it may present an
- alert box. The sound isn’t limited to a single beep but may be any sequence of tones,
- and may occur either alone or along with an alert box. As an error is repeated, there
- can also be a change in which button is the default button (perhaps from OK to Cancel).
- You can specify different responses for up to four occurrences of the same alert.
-
- With Dialog Manager routines, you can create dialog boxes or invoke alerts. The
- Dialog Manager gets most of the descriptive information about the dialogs and alerts
- from resources in a resource file. The Dialog Manager calls the Resource Manager to
- read what it needs from the resource file into memory as necessary. In some cases you
- can modify the information after it’s been read into memory.
-
- Four routines—HideDItem, ShowDItem, FindDItem, and UpdtDialog—have been added to the
- Dialog Manager.
-
- Advanced programmers: The standard filterProc function called by
- ModalDialog now returns 1 in itemHit and a
- function result of TRUE only if the first item
- is enabled.
-
- Automatic scrolling is supported in editText items.
-
- _______________________________________________________________________________
-
-
- æKY Dialog…and…Alert…Windows
- æC »DIALOG AND ALERT WINDOWS DialogManager
- _______________________________________________________________________________
-
- A dialog box appears in a dialog window. When you call a Dialog Manager routine to
- create a dialog, you supply the same information as when you create a window with a
- Window Manager routine. For example, you supply the window definition ID, which
- determines how the window looks and behaves, and a rectangle that becomes the portRect
- of the window’s grafPort. You specify the window’s plane (which, by convention,
- should initially be the frontmost) and whether the window is visible or invisible.
- The dialog window is created as specified.
-
- You can manipulate a dialog window just like any other window with Window Manager or
- QuickDraw routines, showing it, hiding it, moving it, changing its size or plane, or
- whatever— all, of course, in conformance with the Macintosh User Interface Guidelines.
- The Dialog Manager observes the clipping region of the dialog window’s grafPort, so
- if you want clipping to occur, you can set this region with a QuickDraw routine.
-
- Similarly, an alert box appears in an alert window. You don’t have the same flexibility
- in defining and manipulating an alert window, however. The Dialog Manager chooses the
- window definition ID, so that all alert windows will have the standard appearance and
- behavior. The size and location of the box are supplied as part of the definition of
- the alert and are not easily changed. You don’t specify the alert window’s plane; it
- always comes up in front of all other windows. Since an alert box requires the user
- to respond before doing anything else, and the response makes the box go away, the
- application doesn’t do any manipulation of the alert window.
-
-
- Figure 4 illustrates a document window, dialog window, and alert window, all overlapping
- on the desktop.
-
- •••Refer to Figure 4.•••
-
- Figure 4–Dialog and Alert Windows
-
- _______________________________________________________________________________
-
-
- æKY Dialogs…Alerts…and…Resources
- æC »DIALOGS, ALERTS, AND RESOURCES DialogManager
- _______________________________________________________________________________
-
- To create a dialog, the Dialog Manager needs the same information about the dialog
- window as the Window Manager needs when it creates a new window: The window definition
- ID along with other information specific to this window. The Dialog Manager also
- needs to know what items the dialog box contains. You can store the needed information
- as a resource in a resource file and pass the resource ID to a function that will
- create the dialog. This type of resource, which is called a dialog template, is
- analogous to a window template, and the function, GetNewDialog, is similar to the
- Window Manager function GetNewWindow. The Dialog Manager calls the Resource Manager
- to read the dialog template from the resource file. It then incorporates the information
- in the template into a dialog data structure in memory, called a dialog record.
-
- Similarly, the data that the Dialog Manager needs to create an alert is stored in an
- alert template in a resource file. The various routines for invoking alerts require
- the resource ID of the alert template as a parameter.
-
- The information about all the items (text, controls, or graphics) in a dialog or
- alert box is stored in an item list in a resource file. The resource ID of the item
- list is included in the dialog or alert template. The item list in turn contains the
- resource IDs of any icons or QuickDraw pictures in the dialog or alert box, and
- possibly the resource IDs of control templates for controls in the box. After calling
- the Resource Manager to read a dialog or alert template into memory, the Dialog
- Manager calls it again to read in the item list. It then makes a copy of the item
- list and uses that copy; for this reason, item lists should always be purgeable
- resources. Finally, the Dialog Manager calls the Resource Manager to read in any
- individual items as necessary.
-
- If desired, the application can gain some additional flexibility by calling the
- Resource Manager directly to read templates, item lists, or items from a resource
- file. For example, you can read in a dialog or alert template directly and modify
- some of the information in it before calling the routine to create the dialog or
- alert. Or, as an alternative to using a dialog template, you can read in a dialog’s
- item list directly and then pass a handle to it along with other information to a
- function that will create the dialog (NewDialog, analogous to the Window Manager
- function NewWindow).
-
- Note: The use of dialog templates is recommended wherever possible; like
- window templates, they isolate descriptive information from your
- application code for ease of modification or translation to other
- languages.
-
- _______________________________________________________________________________
-
-
- æKY Color…Alert…and…Dialog…Resources
- æC »COLOR ALERT AND DIALOG RESOURCES DialogManager
- _______________________________________________________________________________
-
- You don’t have to call any new routines to create color alert or dialog boxes. Additional
- resources of types 'actb', 'dctb', and 'ictb' complement the existing 'ALRT', 'DLOG',
- and 'DITL' resources, and provide all the information needed to color dialog windows,
- controls, and text.
-
- To create a dialog or alert box, the Dialog Manager needs the same information about
- the box as the Window Manager needs when it creates a new window. The structure of
- dialog color tables and alert color tables is similar to the window color table
- described in the Window Manager chapter, as shown in
- Figure 5.
-
- •••Refer to Figure 5.•••
-
- Figure 5–Color Table for Dialogs and Alerts.
-
- The calls Alert, CautionAlert, StopAlert, and NoteAlert look for a resource of type
- 'actb' with the same resource ID as the alert. GetNewDialog looks for a resource of
- type 'dctb' with the same resource ID as the dialog. These resources contain color
- tables identical to the 'wctb' color tables described in the Window Manager GetNewCWindow
- call. If an 'actb' or 'dctb' resource is present, then the window created will be a
- cGrafPort, created with a NewCWindow call. If the ctSize field of a 'dctb' or 'actb'
- resource is –1, the default window colors will be used.
-
- To include a color icon in a dialog box, add a resource of type 'cicn' with the same
- resource ID as an old-style icon. The Dialog Manager will then access the icon with
- the QuickDraw routine GetCIcon.
-
- To include a version 2 picture in a dialog, create a color table for the dialog to
- cause the dialog to use a cGrafPort. See the Color QuickDraw chapter for more information
- on the use of color pictures.
-
- To color controls in a dialog, or to change the color, style, font, or size of text
- within a dialog, include an 'ictb' resource as described in the following section.
-
- Color table resources 'actb' and 'dctb' are treated the same as 'ALRT' resources and
- 'DLOG' resources. The 'ictb' resource is handled just like the
- 'DITL' resource. These resources are preloaded and made nonpurgeable by CouldAlert
- and CouldDialog, and their original purge state is restored by FreeAlert and FreeDialog.
-
- _______________________________________________________________________________
-
-
- æKY Item…Lists…in…Memory
- æC »ITEM LISTS IN MEMORY DialogManager
- _______________________________________________________________________________
-
- This section discusses the contents of an item list once it’s been read into memory
- from a resource file and the Dialog Manager has set it up as necessary to be able to
- work with it.
-
- An item list in memory contains the following information for each item:
-
- • The type of item. This includes not only whether the item is a control,
- text, or whatever, but also whether the Dialog Manager should return to
- the application when the item is clicked.
- • A handle to the item or, for special application-defined items, a
- pointer to a procedure that draws the item.
- • A display rectangle, which determines the location of the item within
- the dialog or alert box.
-
- These are discussed below along with item numbers, which identify particular items in
- the item list.
-
- There’s a Dialog Manager procedure that, given a pointer to a dialog record and an
- item number, sets or returns that item’s type, handle (or procedure pointer), and
- display rectangle.
-
- _______________________________________________________________________________
-
- »Item Types
-
- The item type is specified by a predefined constant or combination of constants, as
- listed below. Figure 6 illustrates some of these item types.
-
- •••Refer to Figure 6.•••
-
- Figure 6–Item Types
-
- Item type Meaning
-
- ctrlItem+btnCtrl A standard button control.
- ctrlItem+chkCtrl A standard check box control.
- ctrlItem+radCtrl A standard radio button control.
- ctrlItem+resCtrl A control defined in a control template
- in a resource file.
- statText Static text; text that cannot be edited.
- editText (Dialogs only) Text that can be edited;
- the Dialog Manager accepts text typed by
- the user and allows editing.
- iconItem An icon.
- picItem A QuickDraw picture.
- userItem (Dialogs only) An application-defined item,
- such as a picture whose appearance changes.
- itemDisable+<any The item is disabled (the Dialog Manager doesn’t
- of the above> report events involving this item).
-
- The text of an editText item may initially be either default text or empty. Text
- entry and editing is handled in the conventional way, as in TextEdit—in fact, the
- Dialog Manager calls TextEdit to handle it:
-
- • Clicking in the item displays a blinking vertical bar, indicating
- an insertion point where text may be entered.
- • Dragging over text in the item selects that text, and double-clicking
- selects a word; the selection is highlighted and then replaced by
- what the user types.
- • Clicking or dragging while holding down the Shift key extends or
- shortens the current selection.
- • The Backspace key deletes the current selection or the character
- preceding the insertion point.
-
- The Tab key advances to the next editText item in the item list, wrapping around to
- the first if there aren’t any more. In an alert box or a modal dialog box (regardless
- of whether it contains an editText item), the Return key or Enter key has the same
- effect as clicking the default button; for alerts, the default button is identified
- in the alert template, whereas for modal dialogs it’s always the first item in the
- item list.
-
- If itemDisable is specified for an item, the Dialog Manager doesn’t let the application
- know about events involving that item. For example, you may not have to be informed
- every time the user types a character or clicks in an editText item, but may only
- need to look at the text when the OK button is clicked. In this case, the editText
- item would be disabled. Standard buttons and check boxes should always be enabled, so
- your application will know when they’ve been clicked.
-
- Warning: Don’t confuse disabling a control with making one “inactive”
- with the Control Manager procedure HiliteControl: When you
- want a control not to respond at all to being clicked, you
- make it inactive. An inactive control is highlighted to show
- that it’s inactive, while disabling a control doesn’t affect
- its appearance.
-
- _______________________________________________________________________________
-
- »Item Handle or Procedure Pointer
-
- The item list contains the following information for the various types of items:
-
- Item type Contents
-
- any ctrlItem A control handle
- statText A handle to the text
- editText A handle to the current text
- iconItem A handle to the icon
- picItem A picture handle
- userItem A procedure pointer
-
- The procedure for a userItem draws the item; for example, if the item is a clock, it
- will draw the clock with the current time displayed. When this procedure is called,
- the current port will have been set by the Dialog Manager to the dialog window’s
- grafPort. The procedure must have two parameters, a window pointer and an item number.
- For example, this is how it would be declared if it were named MyItem:
-
- PROCEDURE MyItem (theWindow: WindowPtr; itemNo: INTEGER);
-
- TheWindow is a pointer to the dialog window; in case the procedure draws in more than
- one dialog window, this parameter tells it which one to draw in. ItemNo is the item
- number; in case the procedure draws more than one item, this parameter tells it which
- one to draw.
-
- _______________________________________________________________________________
-
- »Display Rectangle
-
- Each item in the item list is displayed within its display rectangle:
-
- • For controls, the display rectangle becomes the control’s
- enclosing rectangle.
- • For an editText item, it becomes TextEdit’s destination rectangle
- and view rectangle. Word wraparound occurs, and the text is clipped
- if there’s more than will fit in the rectangle. In addition, the
- Dialog Manager uses the QuickDraw procedure FrameRect to draw a
- rectangle three pixels outside the display rectangle.
- • StatText items are displayed in exactly the same way as editText
- items, except that a rectangle isn’t drawn outside the display rectangle.
- • Icons and QuickDraw pictures are scaled to fit the display rectangle.
- For pictures, the Window Manager calls the QuickDraw procedure
- DrawPicture and passes it the display rectangle.
- • If the procedure for a userItem draws outside the item’s display
- rectangle, the drawing is clipped to the display rectangle.
-
- Note: Clicking anywhere within the display rectangle is considered a
- click in that item. If display rectangles overlap, a click in
- the overlapping area is considered a click in whichever item
- comes first in the item list.
-
- By giving an item a display rectangle that’s off the screen, you can make the item
- invisible. This might be useful, for example, if your application needs to display a
- number of dialog boxes that are similar except that one item is missing or different
- in some of them. You can use a single dialog box in which the item or items that
- aren’t currently relevant are invisible. To remove an item or make one reappear, you
- just change its display rectangle (and call the Window Manager procedure InvalRect to
- accumulate the changed area into the dialog window’s update region). The QuickDraw
- procedure OffsetRect is convenient for moving an item off the screen and then on
- again later. Note the following, however:
-
- • You shouldn’t make an editText item invisible, because it may cause
- strange things to happen. If one of several editText items is invisible,
- for example, pressing the Tab key may make the insertion point disappear.
- However, if you do make this type of item invisible, remember that the
- changed area includes the rectangle that’s three pixels outside the
- item’s display rectangle.
- • The rectangle for a statText item must always be at least as wide as
- the first character of the text; a good rule of thumb is to make it
- at least 20 pixels wide.
- • To change text in a statText item, it’s easier to use the Dialog
- Manager procedure ParamText (as described later in the “Dialog Manager
- Routines” section).
-
- _______________________________________________________________________________
-
- »Item Numbers
-
- Each item in an item list is identified by an item number, which is simply the index
- of the item in the list (starting from 1). By convention, the first item in an alert’s
- item list should be the OK button (or, if none, then one of the buttons that will
- perform the command) and the second item should be the Cancel button. The Dialog
- Manager provides predefined constants equal to the item numbers for OK and Cancel:
-
- CONST ok = 1;
- cancel = 2;
-
- In a modal dialog’s item list, the first item is assumed to be the dialog’s default
- button; if the user presses the Return key or Enter key, the Dialog Manager normally
- returns item number 1, just as when that item is actually clicked. To conform to the
- Macintosh User Interface Guidelines, the application should boldly outline the dialog’s
- default button if it isn’t the OK button. The best way to do this is with a userItem.
- To allow for changes in the default button’s size or location, the userItem should
- identify which button to outline by its item number and then use that number to get
- the button’s display rectangle. The following QuickDraw calls will outline the rectangle
- in the standard way:
-
- PenSize(3,3);
- InsetRect(displayRect,–4,–4);
- FrameRoundRect(displayRect,16,16)
-
- Warning: If the first item in a modal dialog’s item list isn’t an OK
- button and you don’t boldly outline it, you should set up the
- dialog to ignore Return and Enter. To learn how to do this,
- see ModalDialog under “Handling Dialog Events” in the “Dialog
- Manager Routines” section.
-
- _______________________________________________________________________________
-
-
- æKY Color…Dialog…Item…Lists
- æC »COLOR DIALOG ITEM LISTS DialogManager
- _______________________________________________________________________________
-
- This section discusses the contents of an item list after it’s been read into memory
- from a resource file. If a resource of type 'ictb' is present with the same resource
- ID as the 'DITL' resource (in addition to the presence of the
- 'dctb' or 'actb' resources), then the statText, editText, and control items in the
- dialog or alert boxes are drawn using the colors and text styles indicated by the
- item color table record contained in the resource.
-
- Note: Neither the display device nor the dialog box needs to be in color,
- but a dialog or alert color table must exist to include an item color
- table (even if the item color table only describes statText and editText
- style changes and has no actual color information).
-
- Figure 7 shows how a dialog color table stores item color table records.
-
- •••Refer to Figure 7.•••
-
- Figure 7–Color Table for Dialogs and Alerts.
-
- The record starts with an array of two-word entries for each item in the matching
- dialog item list. The first word (itemCData) is the length of the entry if the item
- is a control, or it is a word of flags if the item is an editText or statText item.
- The second word (itemCOffset) is an offset from the beginning of the record to the
- color item entry. This color record is used only for controls and text; icons and
- pictures have a different method of describing associated colors. Set the itemCData
- and itemCOffset fields to zero for controls or text without colors or font changes.
-
- If the item is an editText or statText item, the bits in the itemCData field determine
- which fields of the text style record to use; these bit equates are listed in the
- following table.
-
- Bit Meaning
- 0 Change the font family
- 1 Change the font face
- 2 Change the font size
- 3 Change the font forecolor
- 4 Add the font size
- 13 Change the font backcolor
- 14 Change the font mode
- 15 The font field is an offset to the name.
-
- Note: Multiple text items can share the same font name.
-
- _______________________________________________________________________________
-
- The itemCData field for text items contains a superset of the flags passed as the
- mode word to the TextEdit routine TESetStyle. The constants defined for that routine
- include:
-
- CONST
-
- { Constants for TextEdit and dialog boxes }
-
- TEdoFont = 1; {set font (family) number}
- TEdoFace = 2; {set character style}
- TEdoSize = 4; {set type size}
- TEdoColor = 8; {set foreground color}
- TEdoAll = 15; {set all attributes}
- TEaddSize = 16; {adjust type size}
-
- { Constants for dialog boxes only }
-
- doBColor = 8192; {set backgound color}
- doMode = 16384; {set txMode}
- doFontName = 32768; {set txFont from name}
-
- The text style record indicated by itemCOffset must be 20 bytes long, as shown in
- Figure 7. Multiple statText and editText items can use the same text style record. To
- display text in the standard font, color, size, and style, set the itemCData and
- itemCOffset to zero. Allocate space for all fields in the style table, even if they
- are not used. Even if only the first few items of the dialog box have color style
- information, there must be room for all of the items actually in the box (with the
- data and offset words of the unused entries set to zero).
-
- For controls, the colors are described by a color table identical to the contents of
- a 'cctb' resource used by a GetNewCControl call. Multiple controls can use the same
- color table. To display a control in the default colors, set the itemCData and itemCOffset
- fields to zero. The length of the control color table should be the header size of
- eight bytes plus the eight-byte ColorSpec record for each entry in the color table.
-
- The doFontName array is optional. However, it’s important to point to the name of the
- font instead of just including the font number. Fonts may be renumbered by font
- installers like the Font/DA Mover as the fonts are moved, so it is safest to rely on
- getting the right font by referring to the name.
-
- •••Refer to Figure 8.•••
-
- Figure 8–Sample Dialog with Color Dialog Items (Color Version).
-
- •••Refer to Figure 9.•••
-
- Figure 9–Sample Dialog with Color Dialog Items (B/W Version).
-
- _______________________________________________________________________________
-
-
- æKY Using…Color…Dialogs…and…Alerts
- æC »USING COLOR DIALOGS AND ALERTS DialogManager
- _______________________________________________________________________________
-
- The dialog box shown in Figure 8 contains 12 different dialog items. Some of these
- items—the OK and Cancel buttons, the radio buttons and the check box, and the editText
- and statText items—contain color information. The table shown in the figure contains
- the hexadecimal description of the dialog items. PicItems, iconItems, resCtrls and
- userItems should have zeroed entries for both fields. All items in the dialog should
- have a field, whether or not the item uses the new features.
-
- Your application can create a dialog or alert, with color dialog items, within a
- resource file, and then use the GetNewDialog routine with the dialog’s resource ID.
- You can also use the NewCDialog routine to create a dialog or alert within an application,
- passing a handle to the dialog’s item list.
-
- _______________________________________________________________________________
-
-
- æKY Dialog…Records
- æC »DIALOG RECORDS DialogManager
- _______________________________________________________________________________
-
- To create a dialog, you pass information to the Dialog Manager in a dialog template
- and in individual parameters, or only in parameters; in either case, the Dialog
- Manager incorporates the information into a dialog record. The dialog record contains
- the window record for the dialog window, a handle to the dialog’s item list, and some
- additional fields. The Dialog Manager creates the dialog window by calling the Window
- Manager function NewWindow and then setting the window class in the window record to
- indicate that it’s a dialog window. The routine that creates the dialog returns a
- pointer to the dialog record, which you use thereafter to refer to the dialog in
- Dialog Manager routines or even in Window Manager or QuickDraw routines (see “Dialog
- Pointers” below). The Dialog Manager provides routines for handling events in the
- dialog window and disposing of the dialog when you’re done.
-
- The data type for a dialog record is called DialogRecord. You can do all the necessary
- operations on a dialog without accessing the fields of the dialog record directly;
- for advanced programmers, however, the exact structure of a dialog record is given
- under “The DialogRecord Data Type” below.
-
- _______________________________________________________________________________
-
- »Dialog Pointers
-
- There are two types of dialog pointer, DialogPtr and DialogPeek, analogous to the
- window pointer types WindowPtr and WindowPeek. Most programmers will only need to use
- DialogPtr.
-
- The Dialog Manager defines the following type of dialog pointer:
-
- TYPE DialogPtr = WindowPtr;
-
- It can do this because the first field of a dialog record contains the window record
- for the dialog window. This type of pointer can be used to access fields of the
- window record or can be passed to Window Manager routines that expect window pointers
- as parameters. Since the WindowPtr data type is itself defined as GrafPtr, this type
- of dialog pointer can also be used to access fields of the dialog window’s grafPort
- or passed to QuickDraw routines that expect pointers to grafPorts as parameters.
-
- For programmers who want to access dialog record fields beyond the window record, the
- Dialog Manager also defines the following type of dialog pointer:
-
- TYPE DialogPeek = ^DialogRecord;
-
- Assembly-language note: From assembly language, of course, there’s no
- type checking on pointers, and the two types
- of pointer are equal.
-
- _______________________________________________________________________________
-
- »The DialogRecord Data Type
-
- For those who want to know more about the data structure of a dialog record, the
- exact structure is given here.
-
- TYPE DialogRecord = RECORD
- window: WindowRecord; {dialog window}
- items: Handle; {item list}
- textH: TEHandle; {current editText item}
- editField: INTEGER; {editText item number minus 1}
- editOpen: INTEGER; {used internally}
- aDefItem: INTEGER {default button item number}
- END;
-
- The window field contains the window record for the dialog window. The items field
- contains a handle to the item list used for the dialog. (Remember that after reading
- an item list from a resource file, the Dialog Manager makes a copy of it and uses
- that copy.)
-
- Note: To get or change information about an item in a dialog, you pass the
- dialog pointer and the item number to a Dialog Manager procedure.
- You’ll never access information directly through the handle to the
- item list.
-
- The Dialog Manager uses the next three fields when there are one or more editText
- items in the dialog. If there’s more than one such item, these fields apply to the
- one that currently is selected or displays the insertion point. The textH field
- contains the handle to the edit record used by TextEdit. EditField is 1 less than the
- item number of the current editText item, or –1 if there’s no editText item in the
- dialog. The editOpen field is used internally by the Dialog Manager.
-
- Note: Actually, a single edit record is shared by all editText items; any
- changes you make to it will apply to all such items. See the TextEdit
- chapter for details about what kinds of changes you can make.
-
- The aDefItem field is used for modal dialogs and alerts, which are treated internally
- as special modal dialogs. It contains the item number of the default button. The
- default button for a modal dialog is the first item in the item list, so this field
- contains 1 for modal dialogs. The default button for an alert is specified in the
- alert template; see the following section for more information.
-
- _______________________________________________________________________________
-
-
- æKY Alerts
- æC »ALERTS DialogManager
- _______________________________________________________________________________
-
- When you call a Dialog Manager routine to invoke an alert, you pass it the resource
- ID of the alert template, which contains the following:
-
- • A rectangle, given in global coordinates, which determines the alert
- window’s size and location. It becomes the portRect of the window’s
- grafPort. To allow for the menu bar and the border around the portRect,
- the top coordinate of the rectangle should be at least 25 points below
- the top of the screen.
- • The resource ID of the item list for the alert.
- • Information about exactly what should happen at each stage of the alert.
-
- Every alert has four stages, corresponding to consecutive occurrences of the alert:
- The first three stages correspond to the first three occurrences, while the fourth
- stage includes the fourth occurrence and any beyond the fourth. (The Dialog Manager
- compares the current alert’s resource ID to the last alert’s resource ID to determine
- whether it’s the same alert.) The actions for each stage are specified by the following
- three pieces of information:
-
- • which is the default button—the OK button (or, if none, a button that
- will perform the command) or the Cancel button
- • whether the alert box is to be drawn
- • which of four sounds should be emitted at this stage of the alert
-
- The alert sounds are determined by a sound procedure that emits one of up to four
- tones or sequences of tones. The sound procedure has one parameter, an integer from 0
- to 3; it can emit any sound for each of these numbers, which identify the sounds in
- the alert template. For example, you might declare a sound procedure named MySound as
- follows:
-
- PROCEDURE MySound (soundNo: INTEGER);
-
- If you don’t write your own sound procedure, the Dialog Manager uses the standard
- one: Sound number 0 represents no sound and sound numbers 1 through 3 represent the
- corresponding number of short beeps, each of the same pitch and duration. The volume
- of each beep depends on the current speaker volume setting, which the user can adjust
- with the Control Panel desk accessory. If the user has set the speaker volume to 0,
- the menu bar will blink in place of each beep.
-
- For example, if the second stage of an alert is to cause a beep and no alert box, you
- can just specify the following for that stage in the alert template: Don’t draw the
- alert box, and use sound number 1. If instead you want, say, two successive beeps of
- different pitch, you need to write a procedure that will emit that sound for a particular
- sound number, and specify that number in the alert template. The Macintosh Operating
- System includes routines for emitting sound; see the Sound Driver chapter, and also
- the simple SysBeep procedure in the Operating System Utilties chapter. (The standard
- sound procedure calls SysBeep.)
-
- Note: When the Dialog Manager detects a click outside an alert box or a
- modal dialog box, it emits sound number 1; thus, for consistency
- with the Macintosh User Interface Guidelines, sound number 1 should
- always be a single beep.
-
- Internally, alerts are treated as special modal dialogs. The alert routine creates
- the alert window by calling NewDialog. The Dialog Manager works from the dialog
- record created by NewDialog, just as when it operates on a dialog window, but it
- disposes of the window before returning to the application. Normally your application
- won’t access the dialog record for an alert; however, there is a way that this can
- happen: For any alert, you can specify a procedure that will be executed repeatedly
- during the alert, and this procedure may access the dialog record. For details, see
- the alert routines under
- “Invoking Alerts” in the “Dialog Manager Routines” section.
-
- _______________________________________________________________________________
-
-
- æKY Using…the…Dialog…Manager
- æC »USING THE DIALOG MANAGER DialogManager
- _______________________________________________________________________________
-
- Before using the Dialog Manager, you must initialize QuickDraw, the Font Manager, the
- Window Manager, the Menu Manager, and TextEdit, in that order. The first Dialog
- Manager routine to call is InitDialogs, which initializes the Dialog Manager. If you
- want the font in your dialog and alert windows to be other than the system font, call
- SetDAFont to change the font.
-
- Where appropriate in your program, call NewDialog or GetNewDialog to create any
- dialogs you need. Usually you’ll call GetNewDialog, which takes descriptive information
- about the dialog from a dialog template in a resource file. You can instead pass the
- information in individual parameters to NewDialog. In either case, you can supply a
- pointer to the storage for the dialog record or let it be allocated by the Dialog
- Manager. When you no longer need a dialog, you’ll usually call CloseDialog if you
- supplied the storage, or DisposDialog if not.
-
- In most cases, you probably won’t have to make any changes to the dialogs from the
- way they’re defined in the resource file. However, if you should want to modify an
- item in a dialog, you can call GetDItem to get the information about the item and
- SetDItem to change it. In particular, SetDItem is the routine to use for installing a
- userItem. In some cases it may be appropriate to call some other Toolbox routine to
- change the item; for example, to change or move a control in a dialog, you would get
- its handle from GetDItem and then call the appropriate Control Manager routine. There
- are also two procedures specifically for accessing or setting the content of a text
- item in a dialog box: GetIText and SetIText.
-
- To handle events in a modal dialog, just call the ModalDialog procedure after putting
- up the dialog box. If your application includes any modeless dialog boxes, you’ll
- pass events to IsDialogEvent to learn whether they need to be handled as part of a
- dialog, and then usually call DialogSelect if so. Before calling DialogSelect, however,
- you should check whether the user has given the keyboard equivalent of a command, and
- you may want to check for other special cases, depending on your application. You can
- support the use of the standard editing commands in a modeless dialog’s editText
- items with DlgCut, DlgCopy, DlgPaste, and DlgDelete.
-
- A dialog box that contains editText items normally comes up with the insertion point
- in the first such item in its item list. You may instead want to bring up a dialog
- box with text selected in an editText item, or to cause an insertion point or text
- selection to reappear after the user has made an error in entering text. For example,
- the user who accidentally types nonnumeric input when a number is required can be
- given the opportunity to type the entry again. The SelIText procedure makes this
- possible.
-
- For alerts, if you want other sounds besides the standard ones (up to three short
- beeps), write your own sound procedure and call ErrorSound to ma